From e01d393fed55b25fb11d4db62aa6ecd4f676f8c3 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Thu, 8 Jan 2026 16:16:39 +0100 Subject: [PATCH 01/13] chore: remove the forked pkgs --- pkg/fork.sh | 29 - pkg/quicktest/.github/dependabot.yaml | 14 - pkg/quicktest/.github/workflows/ci.yaml | 25 - pkg/quicktest/.gitignore | 1 - pkg/quicktest/.godocdown.template | 13 - pkg/quicktest/LICENSE | 21 - pkg/quicktest/README.md | 347 --- pkg/quicktest/checker.go | 799 ------ pkg/quicktest/checker_err.go | 92 - pkg/quicktest/checker_err_test.go | 249 -- pkg/quicktest/checker_test.go | 3110 ----------------------- pkg/quicktest/cleanup_test.go | 91 - pkg/quicktest/comment.go | 31 - pkg/quicktest/comment_test.go | 27 - pkg/quicktest/deferpanic_test.go | 44 - pkg/quicktest/doc.go | 340 --- pkg/quicktest/error.go | 35 - pkg/quicktest/error_test.go | 58 - pkg/quicktest/export_test.go | 8 - pkg/quicktest/format.go | 91 - pkg/quicktest/format_test.go | 146 -- pkg/quicktest/iter.go | 55 - pkg/quicktest/mapiter.go | 29 - pkg/quicktest/patch.go | 72 - pkg/quicktest/patch_go1.14.go | 42 - pkg/quicktest/patch_go1.14_test.go | 43 - pkg/quicktest/patch_go1.17.go | 27 - pkg/quicktest/patch_go1.17_test.go | 36 - pkg/quicktest/patch_test.go | 122 - pkg/quicktest/qtsuite/suite.go | 122 - pkg/quicktest/qtsuite/suite_test.go | 148 -- pkg/quicktest/quicktest.go | 370 --- pkg/quicktest/quicktest_test.go | 753 ------ pkg/quicktest/race_test.go | 90 - pkg/quicktest/report.go | 248 -- pkg/quicktest/report_test.go | 185 -- pkg/slogassert/.gitignore | 2 - pkg/slogassert/LICENSE | 19 - pkg/slogassert/README.md | 193 -- pkg/slogassert/assertions.go | 485 ---- pkg/slogassert/assertions_test.go | 228 -- pkg/slogassert/default.go | 120 - pkg/slogassert/default_test.go | 105 - pkg/slogassert/null_handler.go | 32 - pkg/slogassert/null_handler_test.go | 10 - pkg/slogassert/pre-commit | 13 - pkg/slogassert/slogassert.go | 322 --- pkg/slogassert/slogassert_test.go | 284 --- 48 files changed, 9726 deletions(-) delete mode 100755 pkg/fork.sh delete mode 100644 pkg/quicktest/.github/dependabot.yaml delete mode 100644 pkg/quicktest/.github/workflows/ci.yaml delete mode 100644 pkg/quicktest/.gitignore delete mode 100644 pkg/quicktest/.godocdown.template delete mode 100644 pkg/quicktest/LICENSE delete mode 100644 pkg/quicktest/README.md delete mode 100644 pkg/quicktest/checker.go delete mode 100644 pkg/quicktest/checker_err.go delete mode 100644 pkg/quicktest/checker_err_test.go delete mode 100644 pkg/quicktest/checker_test.go delete mode 100644 pkg/quicktest/cleanup_test.go delete mode 100644 pkg/quicktest/comment.go delete mode 100644 pkg/quicktest/comment_test.go delete mode 100644 pkg/quicktest/deferpanic_test.go delete mode 100644 pkg/quicktest/doc.go delete mode 100644 pkg/quicktest/error.go delete mode 100644 pkg/quicktest/error_test.go delete mode 100644 pkg/quicktest/export_test.go delete mode 100644 pkg/quicktest/format.go delete mode 100644 pkg/quicktest/format_test.go delete mode 100644 pkg/quicktest/iter.go delete mode 100644 pkg/quicktest/mapiter.go delete mode 100644 pkg/quicktest/patch.go delete mode 100644 pkg/quicktest/patch_go1.14.go delete mode 100644 pkg/quicktest/patch_go1.14_test.go delete mode 100644 pkg/quicktest/patch_go1.17.go delete mode 100644 pkg/quicktest/patch_go1.17_test.go delete mode 100644 pkg/quicktest/patch_test.go delete mode 100644 pkg/quicktest/qtsuite/suite.go delete mode 100644 pkg/quicktest/qtsuite/suite_test.go delete mode 100644 pkg/quicktest/quicktest.go delete mode 100644 pkg/quicktest/quicktest_test.go delete mode 100644 pkg/quicktest/race_test.go delete mode 100644 pkg/quicktest/report.go delete mode 100644 pkg/quicktest/report_test.go delete mode 100644 pkg/slogassert/.gitignore delete mode 100644 pkg/slogassert/LICENSE delete mode 100644 pkg/slogassert/README.md delete mode 100644 pkg/slogassert/assertions.go delete mode 100644 pkg/slogassert/assertions_test.go delete mode 100644 pkg/slogassert/default.go delete mode 100644 pkg/slogassert/default_test.go delete mode 100644 pkg/slogassert/null_handler.go delete mode 100644 pkg/slogassert/null_handler_test.go delete mode 100755 pkg/slogassert/pre-commit delete mode 100644 pkg/slogassert/slogassert.go delete mode 100644 pkg/slogassert/slogassert_test.go diff --git a/pkg/fork.sh b/pkg/fork.sh deleted file mode 100755 index 99f9b5e0..00000000 --- a/pkg/fork.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash - -function replace_in_go_files() { - local search=$1 - local replace=$2 - find . -type f -name "*.go" -exec sed -i "s|$search|$replace|g" {} + -} - -function fix_project() { - rm -rf .git go.mod go.sum - - replace_in_go_files '"testing"' 'testing "github.com/CodSpeedHQ/codspeed-go/compat/testing"' - replace_in_go_files '"testing/slogtest"' 'slogtest "github.com/CodSpeedHQ/codspeed-go/compat/testing/slogtest"' - - go mod tidy - go fmt ./... -} - -git clone -b v0.3.4 https://github.com/thejerf/slogassert.git -pushd slogassert -replace_in_go_files '"github.com/thejerf/slogassert' '"github.com/CodSpeedHQ/codspeed-go/pkg/slogassert' -fix_project -popd - -git clone -b v1.14.6 https://github.com/frankban/quicktest -pushd quicktest -replace_in_go_files '"github.com/frankban/quicktest' '"github.com/CodSpeedHQ/codspeed-go/pkg/quicktest' -fix_project -popd diff --git a/pkg/quicktest/.github/dependabot.yaml b/pkg/quicktest/.github/dependabot.yaml deleted file mode 100644 index 0553b12a..00000000 --- a/pkg/quicktest/.github/dependabot.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: 2 -updates: - - - package-ecosystem: "github-actions" - directory: "/" - schedule: - # Check for updates to GitHub Actions every weekday. - interval: "daily" - - - package-ecosystem: "gomod" - directory: "/" - schedule: - # Check for updates to go modules every weekday. - interval: "daily" diff --git a/pkg/quicktest/.github/workflows/ci.yaml b/pkg/quicktest/.github/workflows/ci.yaml deleted file mode 100644 index 3d137a5d..00000000 --- a/pkg/quicktest/.github/workflows/ci.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: CI -on: [push, pull_request] - -jobs: - build_test: - name: Build and Test - strategy: - matrix: - go: ['1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19', '1.20'] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go }} - - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ubuntu-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ubuntu-go- - - name: Test - run: go test -mod readonly -race ./... - - name: Test Verbose - run: go test -mod readonly -race -v ./... diff --git a/pkg/quicktest/.gitignore b/pkg/quicktest/.gitignore deleted file mode 100644 index 722d5e71..00000000 --- a/pkg/quicktest/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.vscode diff --git a/pkg/quicktest/.godocdown.template b/pkg/quicktest/.godocdown.template deleted file mode 100644 index 70c89817..00000000 --- a/pkg/quicktest/.godocdown.template +++ /dev/null @@ -1,13 +0,0 @@ -[![Go Reference](https://pkg.go.dev/badge/github.com/frankban/quicktest.svg)](https://pkg.go.dev/github.com/frankban/quicktest#section-documentation) -[![Build Status](https://github.com/frankban/quicktest/actions/workflows/ci.yaml/badge.svg)](https://github.com/frankban/quicktest/actions/workflows/ci.yaml) - -[//]: # (Generated with: godocdown -template=.godocdown.template -o README.md && sed -i= 's/^# /### /' README.md ) - -# quicktest - -`go get github.com/frankban/quicktest@latest` - -{{ .EmitSynopsis }} - -For a complete API reference, see the -[package documentation](https://pkg.go.dev/github.com/frankban/quicktest#section-documentation). diff --git a/pkg/quicktest/LICENSE b/pkg/quicktest/LICENSE deleted file mode 100644 index 23a294c7..00000000 --- a/pkg/quicktest/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Canonical Ltd. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/pkg/quicktest/README.md b/pkg/quicktest/README.md deleted file mode 100644 index a3017fbf..00000000 --- a/pkg/quicktest/README.md +++ /dev/null @@ -1,347 +0,0 @@ -[![Go Reference](https://pkg.go.dev/badge/github.com/frankban/quicktest.svg)](https://pkg.go.dev/github.com/frankban/quicktest#section-documentation) -[![Build Status](https://github.com/frankban/quicktest/actions/workflows/ci.yaml/badge.svg)](https://github.com/frankban/quicktest/actions/workflows/ci.yaml) - -[//]: # (Generated with: godocdown -template=.godocdown.template -o README.md) - -### quicktest - -`go get github.com/frankban/quicktest@latest` - -Package quicktest provides a collection of Go helpers for writing tests. - -Quicktest helpers can be easily integrated inside regular Go tests, for -instance: - - import qt "github.com/frankban/quicktest" - - func TestFoo(t *testing.T) { - t.Run("numbers", func(t *testing.T) { - c := qt.New(t) - numbers, err := somepackage.Numbers() - c.Assert(err, qt.IsNil) - c.Assert(numbers, qt.DeepEquals, []int{42, 47}) - }) - t.Run("bad wolf error", func(t *testing.T) { - c := qt.New(t) - numbers, err := somepackage.Numbers() - c.Assert(err, qt.ErrorMatches, "bad wolf") - }) - t.Run("nil", func(t *testing.T) { - c := qt.New(t) - got := somepackage.MaybeNil() - c.Assert(got, qt.IsNil, qt.Commentf("value: %v", somepackage.Value)) - }) - } - -### Assertions - -An assertion looks like this, where qt.Equals could be replaced by any available -checker. If the assertion fails, the underlying Fatal method is called to -describe the error and abort the test. - - c := qt.New(t) - c.Assert(someValue, qt.Equals, wantValue) - -If you don’t want to abort on failure, use Check instead, which calls Error -instead of Fatal: - - c.Check(someValue, qt.Equals, wantValue) - -For really short tests, the extra line for instantiating *qt.C can be avoided: - - qt.Assert(t, someValue, qt.Equals, wantValue) - qt.Check(t, someValue, qt.Equals, wantValue) - -The library provides some base checkers like Equals, DeepEquals, Matches, -ErrorMatches, IsNil and others. More can be added by implementing the Checker -interface. Below, we list the checkers implemented by the package in -alphabetical order. - -### All - -All returns a Checker that uses the given checker to check elements of slice or -array or the values of a map. It succeeds if all elements pass the check. On -failure it prints the error from the first index that failed. - -For example: - - c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0) - c.Assert([][]string{{"a", "b"}, {"a", "b"}}, qt.All(qt.DeepEquals), []string{"c", "d"}) - -See also Any and Contains. - -### Any - -Any returns a Checker that uses the given checker to check elements of a slice -or array or the values from a map. It succeeds if any element passes the check. - -For example: - - c.Assert([]int{3,5,7,99}, qt.Any(qt.Equals), 7) - c.Assert([][]string{{"a", "b"}, {"c", "d"}}, qt.Any(qt.DeepEquals), []string{"c", "d"}) - -See also All and Contains. - -### CmpEquals - -CmpEquals checks equality of two arbitrary values according to the provided -compare options. DeepEquals is more commonly used when no compare options are -required. - -Example calls: - - c.Assert(list, qt.CmpEquals(cmpopts.SortSlices), []int{42, 47}) - c.Assert(got, qt.CmpEquals(), []int{42, 47}) // Same as qt.DeepEquals. - -### CodecEquals - -CodecEquals returns a checker that checks for codec value equivalence. - - func CodecEquals( - marshal func(interface{}) ([]byte, error), - unmarshal func([]byte, interface{}) error, - opts ...cmp.Option, - ) Checker - -It expects two arguments: a byte slice or a string containing some -codec-marshaled data, and a Go value. - -It uses unmarshal to unmarshal the data into an interface{} value. It marshals -the Go value using marshal, then unmarshals the result into an interface{} -value. - -It then checks that the two interface{} values are deep-equal to one another, -using CmpEquals(opts) to perform the check. - -See JSONEquals for an example of this in use. - -### Contains - -Contains checks that a map, slice, array or string contains a value. It's the -same as using Any(Equals), except that it has a special case for strings - if -the first argument is a string, the second argument must also be a string and -strings.Contains will be used. - -For example: - - c.Assert("hello world", qt.Contains, "world") - c.Assert([]int{3,5,7,99}, qt.Contains, 7) - -### ContentEquals - -ContentEquals is is like DeepEquals but any slices in the compared values will -be sorted before being compared. - -For example: - - c.Assert([]string{"c", "a", "b"}, qt.ContentEquals, []string{"a", "b", "c"}) - -### DeepEquals - -DeepEquals checks that two arbitrary values are deeply equal. The comparison is -done using the github.com/google/go-cmp/cmp package. When comparing structs, by -default no exported fields are allowed. If a more sophisticated comparison is -required, use CmpEquals (see below). - -Example call: - - c.Assert(got, qt.DeepEquals, []int{42, 47}) - -### Equals - -Equals checks that two values are equal, as compared with Go's == operator. - -For instance: - - c.Assert(answer, qt.Equals, 42) - -Note that the following will fail: - - c.Assert((*sometype)(nil), qt.Equals, nil) - -Use the IsNil checker below for this kind of nil check. - -### ErrorAs - -ErrorAs checks that the error is or wraps a specific error type. If so, it -assigns it to the provided pointer. This is analogous to calling errors.As. - -For instance: - - // Checking for a specific error type - c.Assert(err, qt.ErrorAs, new(*os.PathError)) - - // Checking fields on a specific error type - var pathError *os.PathError - if c.Check(err, qt.ErrorAs, &pathError) { - c.Assert(pathError.Path, Equals, "some_path") - } - -### ErrorIs - -ErrorIs checks that the error is or wraps a specific error value. This is -analogous to calling errors.Is. - -For instance: - - c.Assert(err, qt.ErrorIs, os.ErrNotExist) - -### ErrorMatches - -ErrorMatches checks that the provided value is an error whose message matches -the provided regular expression. - -For instance: - - c.Assert(err, qt.ErrorMatches, `bad wolf .*`) - -### HasLen - -HasLen checks that the provided value has the given length. - -For instance: - - c.Assert([]int{42, 47}, qt.HasLen, 2) - c.Assert(myMap, qt.HasLen, 42) - -### Implements - -Implements checks that the provided value implements an interface. The interface -is specified with a pointer to an interface variable. - -For instance: - - var rc io.ReadCloser - c.Assert(myReader, qt.Implements, &rc) - -### IsFalse - -IsFalse checks that the provided value is false. The value must have a boolean -underlying type. - -For instance: - - c.Assert(false, qt.IsFalse) - c.Assert(IsValid(), qt.IsFalse) - -### IsNil - -IsNil checks that the provided value is nil. - -For instance: - - c.Assert(got, qt.IsNil) - -As a special case, if the value is nil but implements the error interface, it is -still considered to be non-nil. This means that IsNil will fail on an error -value that happens to have an underlying nil value, because that's invariably a -mistake. See https://golang.org/doc/faq#nil_error. - -So it's just fine to check an error like this: - - c.Assert(err, qt.IsNil) - -### IsNotNil - -IsNotNil is a Checker checking that the provided value is not nil. IsNotNil is -the equivalent of qt.Not(qt.IsNil) - -For instance: - - c.Assert(got, qt.IsNotNil) - -### IsTrue - -IsTrue checks that the provided value is true. The value must have a boolean -underlying type. - -For instance: - - c.Assert(true, qt.IsTrue) - c.Assert(myBoolean(false), qt.IsTrue) - -### JSONEquals - -JSONEquals checks whether a byte slice or string is JSON-equivalent to a Go -value. See CodecEquals for more information. - -It uses DeepEquals to do the comparison. If a more sophisticated comparison is -required, use CodecEquals directly. - -For instance: - - c.Assert(`{"First": 47.11}`, qt.JSONEquals, &MyStruct{First: 47.11}) - -### Matches - -Matches checks that a string or result of calling the String method (if the -value implements fmt.Stringer) matches the provided regular expression. - -For instance: - - c.Assert("these are the voyages", qt.Matches, `these are .*`) - c.Assert(net.ParseIP("1.2.3.4"), qt.Matches, `1.*`) - -### Not - -Not returns a Checker negating the given Checker. - -For instance: - - c.Assert(got, qt.Not(qt.IsNil)) - c.Assert(answer, qt.Not(qt.Equals), 42) - -### PanicMatches - -PanicMatches checks that the provided function panics with a message matching -the provided regular expression. - -For instance: - - c.Assert(func() {panic("bad wolf ...")}, qt.PanicMatches, `bad wolf .*`) - -### Satisfies - -Satisfies checks that the provided value, when used as argument of the provided -predicate function, causes the function to return true. The function must be of -type func(T) bool, having got assignable to T. - -For instance: - - // Check that an error from os.Open satisfies os.IsNotExist. - c.Assert(err, qt.Satisfies, os.IsNotExist) - - // Check that a floating point number is a not-a-number. - c.Assert(f, qt.Satisfies, math.IsNaN) - -### Deferred Execution - -The testing.TB.Cleanup helper provides the ability to defer the execution of -functions that will be run when the test completes. This is often useful for -creating OS-level resources such as temporary directories (see c.Mkdir). - -When targeting Go versions that don't have Cleanup (< 1.14), the same can be -achieved using c.Defer. In this case, to trigger the deferred behavior, calling -c.Done is required. For instance, if you create a *C instance at the top level, -you’ll have to add a defer to trigger the cleanups at the end of the test: - - defer c.Done() - -However, if you use quicktest to create a subtest, Done will be called -automatically at the end of that subtest. For example: - - func TestFoo(t *testing.T) { - c := qt.New(t) - c.Run("subtest", func(c *qt.C) { - c.Setenv("HOME", c.Mkdir()) - // Here $HOME is set the path to a newly created directory. - // At the end of the test the directory will be removed - // and HOME set back to its original value. - }) - } - -The c.Patch, c.Setenv, c.Unsetenv and c.Mkdir helpers use t.Cleanup for cleaning -up resources when available, and fall back to Defer otherwise. - -For a complete API reference, see the -[package documentation](https://pkg.go.dev/github.com/frankban/quicktest#section-documentation). diff --git a/pkg/quicktest/checker.go b/pkg/quicktest/checker.go deleted file mode 100644 index 401437a4..00000000 --- a/pkg/quicktest/checker.go +++ /dev/null @@ -1,799 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "encoding/json" - "errors" - "fmt" - "reflect" - "regexp" - "strings" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "github.com/kr/pretty" -) - -// Checker is implemented by types used as part of Check/Assert invocations. -type Checker interface { - // Check checks that the obtained value (got) is correct with respect to - // the checker's arguments (args). On failure, the returned error is - // printed along with the checker arguments and any key-value pairs added - // by calling the note function. Values are pretty-printed unless they are - // of type Unquoted. - // - // When the check arguments are invalid, Check may return a BadCheck error, - // which suppresses printing of the checker arguments. Values added with - // note are still printed. - // - // If Check returns ErrSilent, neither the checker arguments nor the error - // are printed. Again, values added with note are still printed. - Check(got interface{}, args []interface{}, note func(key string, value interface{})) error - - // ArgNames returns the names of all required arguments, including the - // mandatory got argument and any additional args. - ArgNames() []string -} - -// Equals is a Checker checking equality of two comparable values. -// -// For instance: -// -// c.Assert(answer, qt.Equals, 42) -// -// Note that the following will fail: -// -// c.Assert((*sometype)(nil), qt.Equals, nil) -// -// Use the IsNil checker below for this kind of nil check. -var Equals Checker = &equalsChecker{ - argNames: []string{"got", "want"}, -} - -type equalsChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got == args[0]. -func (c *equalsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - defer func() { - // A panic is raised when the provided values are not comparable. - if r := recover(); r != nil { - err = fmt.Errorf("%s", r) - } - }() - want := args[0] - if got == want { - return nil - } - - // Customize error message for non-nil errors. - if _, ok := got.(error); ok && want == nil { - return errors.New("got non-nil error") - } - - // Show error types when comparing errors with different types. - if got, ok := got.(error); ok { - if want, ok := want.(error); ok { - gotType := reflect.TypeOf(got) - wantType := reflect.TypeOf(want) - if gotType != wantType { - note("got type", Unquoted(gotType.String())) - note("want type", Unquoted(wantType.String())) - } - } - return errors.New("values are not equal") - } - - // Show line diff when comparing different multi-line strings. - if got, ok := got.(string); ok { - if want, ok := want.(string); ok { - isMultiLine := func(s string) bool { - i := strings.Index(s, "\n") - return i != -1 && i < len(s)-1 - } - if isMultiLine(got) || isMultiLine(want) { - diff := cmp.Diff(strings.SplitAfter(got, "\n"), strings.SplitAfter(want, "\n")) - note("line diff (-got +want)", Unquoted(diff)) - } - } - } - - return errors.New("values are not equal") -} - -// CmpEquals returns a Checker checking equality of two arbitrary values -// according to the provided compare options. See DeepEquals as an example of -// such a checker, commonly used when no compare options are required. -// -// Example calls: -// -// c.Assert(list, qt.CmpEquals(cmpopts.SortSlices), []int{42, 47}) -// c.Assert(got, qt.CmpEquals(), []int{42, 47}) // Same as qt.DeepEquals. -func CmpEquals(opts ...cmp.Option) Checker { - return &cmpEqualsChecker{ - argNames: []string{"got", "want"}, - opts: opts, - } -} - -type cmpEqualsChecker struct { - argNames - opts cmp.Options -} - -// Check implements Checker.Check by checking that got == args[0] according to -// the compare options stored in the checker. -func (c *cmpEqualsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - defer func() { - // A panic is raised in some cases, for instance when trying to compare - // structs with unexported fields and neither AllowUnexported nor - // cmpopts.IgnoreUnexported are provided. - if r := recover(); r != nil { - err = BadCheckf("%s", r) - } - }() - want := args[0] - if diff := cmp.Diff(got, want, c.opts...); diff != "" { - // Only output values when the verbose flag is set. - note("error", Unquoted("values are not deep equal")) - note("diff (-got +want)", Unquoted(diff)) - note("got", SuppressedIfLong{got}) - note("want", SuppressedIfLong{want}) - return ErrSilent - } - return nil -} - -// DeepEquals is a Checker deeply checking equality of two arbitrary values. -// The comparison is done using the github.com/google/go-cmp/cmp package. -// When comparing structs, by default no exported fields are allowed. CmpEquals -// can be used when more customized compare options are required. -// -// Example call: -// -// c.Assert(got, qt.DeepEquals, []int{42, 47}) -var DeepEquals = CmpEquals() - -// ContentEquals is like DeepEquals but any slices in the compared values will -// be sorted before being compared. -var ContentEquals = CmpEquals(cmpopts.SortSlices(func(x, y interface{}) bool { - // TODO frankban: implement a proper sort function. - return pretty.Sprint(x) < pretty.Sprint(y) -})) - -// Matches is a Checker checking that the provided string or fmt.Stringer -// matches the provided regular expression pattern. -// -// For instance: -// -// c.Assert("these are the voyages", qt.Matches, "these are .*") -// c.Assert(net.ParseIP("1.2.3.4"), qt.Matches, "1.*") -// c.Assert("my multi-line\nnumber", qt.Matches, regexp.MustCompile(`my multi-line\n(string|number)`)) -var Matches Checker = &matchesChecker{ - argNames: []string{"got value", "regexp"}, -} - -type matchesChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is a string or a -// fmt.Stringer and that it matches args[0]. -func (c *matchesChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - pattern := args[0] - switch v := got.(type) { - case string: - return match(v, pattern, "value does not match regexp", note) - case fmt.Stringer: - return match(v.String(), pattern, "value.String() does not match regexp", note) - } - note("value", got) - return BadCheckf("value is not a string or a fmt.Stringer") -} - -func checkFirstArgIsError(got interface{}, note func(key string, value interface{})) error { - if got == nil { - return errors.New("got nil error but want non-nil") - } - _, ok := got.(error) - if !ok { - note("got", got) - return BadCheckf("first argument is not an error") - } - return nil -} - -// ErrorMatches is a Checker checking that the provided value is an error whose -// message matches the provided regular expression pattern. -// -// For instance: -// -// c.Assert(err, qt.ErrorMatches, "bad wolf .*") -// c.Assert(err, qt.ErrorMatches, regexp.MustCompile("bad wolf .*")) -var ErrorMatches Checker = &errorMatchesChecker{ - argNames: []string{"got error", "regexp"}, -} - -type errorMatchesChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is an error whose -// Error() matches args[0]. -func (c *errorMatchesChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - if err := checkFirstArgIsError(got, note); err != nil { - return err - } - - gotErr := got.(error) - return match(gotErr.Error(), args[0], "error does not match regexp", note) -} - -// PanicMatches is a Checker checking that the provided function panics with a -// message matching the provided regular expression pattern. -// -// For instance: -// -// c.Assert(func() {panic("bad wolf ...")}, qt.PanicMatches, "bad wolf .*") -// c.Assert(func() {panic("bad wolf ...")}, qt.PanicMatches, regexp.MustCompile(`bad wolf .*`)) -var PanicMatches Checker = &panicMatchesChecker{ - argNames: []string{"function", "regexp"}, -} - -type panicMatchesChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is a func() that panics -// with a message matching args[0]. -func (c *panicMatchesChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - f := reflect.ValueOf(got) - if f.Kind() != reflect.Func { - note("got", got) - return BadCheckf("first argument is not a function") - } - ftype := f.Type() - if ftype.NumIn() != 0 { - note("function", got) - return BadCheckf("cannot use a function receiving arguments") - } - - defer func() { - r := recover() - if r == nil { - err = errors.New("function did not panic") - return - } - msg := fmt.Sprint(r) - note("panic value", msg) - err = match(msg, args[0], "panic value does not match regexp", note) - }() - - f.Call(nil) - return nil -} - -// IsNil is a Checker checking that the provided value is nil. -// -// For instance: -// -// c.Assert(got, qt.IsNil) -// -// As a special case, if the value is nil but implements the -// error interface, it is still considered to be non-nil. -// This means that IsNil will fail on an error value that happens -// to have an underlying nil value, because that's -// invariably a mistake. -// See https://golang.org/doc/faq#nil_error. -var IsNil Checker = &isNilChecker{ - argNames: []string{"got"}, -} - -type isNilChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is nil. -func (c *isNilChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - if got == nil { - return nil - } - value := reflect.ValueOf(got) - _, isError := got.(error) - if canBeNil(value.Kind()) && value.IsNil() { - if isError { - // It's an error with an underlying nil value. - return fmt.Errorf("error containing nil value of type %T. See https://golang.org/doc/faq#nil_error", got) - } - return nil - } - if isError { - return errors.New("got non-nil error") - } - return errors.New("got non-nil value") -} - -// IsNotNil is a Checker checking that the provided value is not nil. -// IsNotNil is the equivalent of qt.Not(qt.IsNil) -// -// For instance: -// -// c.Assert(got, qt.IsNotNil) -var IsNotNil Checker = ¬Checker{ - Checker: IsNil, -} - -// HasLen is a Checker checking that the provided value has the given length. -// -// For instance: -// -// c.Assert([]int{42, 47}, qt.HasLen, 2) -// c.Assert(myMap, qt.HasLen, 42) -var HasLen Checker = &hasLenChecker{ - argNames: []string{"got", "want length"}, -} - -type hasLenChecker struct { - argNames -} - -// Check implements Checker.Check by checking that len(got) == args[0]. -func (c *hasLenChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - v := reflect.ValueOf(got) - switch v.Kind() { - case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: - default: - note("got", got) - return BadCheckf("first argument has no length") - } - want, ok := args[0].(int) - if !ok { - note("length", args[0]) - return BadCheckf("length is not an int") - } - length := v.Len() - note("len(got)", length) - if length != want { - return fmt.Errorf("unexpected length") - } - return nil -} - -// Implements checks that the provided value implements an interface. The -// interface is specified with a pointer to an interface variable. -// -// For instance: -// -// var rc io.ReadCloser -// c.Assert(myReader, qt.Implements, &rc) -var Implements Checker = &implementsChecker{ - argNames: []string{"got", "want interface pointer"}, -} - -type implementsChecker struct { - argNames -} - -var emptyInterface = reflect.TypeOf((*interface{})(nil)).Elem() - -// Check implements Checker.Check by checking that got implements the -// interface pointed to by args[0]. -func (c *implementsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - if got == nil { - note("error", Unquoted("got nil value but want non-nil")) - note("got", got) - return ErrSilent - } - - if args[0] == nil { - return BadCheckf("want a pointer to an interface variable but nil was provided") - } - wantType := reflect.TypeOf(args[0]) - if wantType.Kind() != reflect.Ptr { - note("want", Unquoted(wantType.String())) - return BadCheckf("want a pointer to an interface variable but a non-pointer value was provided") - } else if wantType.Elem().Kind() != reflect.Interface { - note("want pointer type", Unquoted(wantType.Elem().String())) - return BadCheckf("want a pointer to an interface variable but a pointer to a concrete type was provided") - } else if wantType.Elem() == emptyInterface { - note("want pointer type", Unquoted(wantType.Elem().String())) - return BadCheckf("all types implement the empty interface, want a pointer to a variable that isn't the empty interface") - } - - gotType := reflect.TypeOf(got) - if !gotType.Implements(wantType.Elem()) { - note("error", Unquoted("got value does not implement wanted interface")) - note("got", got) - note("want interface", Unquoted(wantType.Elem().String())) - return ErrSilent - } - - return nil -} - -// Satisfies is a Checker checking that the provided value, when used as -// argument of the provided predicate function, causes the function to return -// true. The function must be of type func(T) bool, having got assignable to T. -// -// For instance: -// -// // Check that an error from os.Open satisfies os.IsNotExist. -// c.Assert(err, qt.Satisfies, os.IsNotExist) -// -// // Check that a floating point number is a not-a-number. -// c.Assert(f, qt.Satisfies, math.IsNaN) -var Satisfies Checker = &satisfiesChecker{ - argNames: []string{"arg", "predicate function"}, -} - -type satisfiesChecker struct { - argNames -} - -// Check implements Checker.Check by checking that args[0](got) == true. -func (c *satisfiesChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - // Original code at - // . - predicate := args[0] - f := reflect.ValueOf(predicate) - ftype := f.Type() - if ftype.Kind() != reflect.Func || ftype.NumIn() != 1 || ftype.NumOut() != 1 || ftype.Out(0).Kind() != reflect.Bool { - note("predicate function", predicate) - return BadCheckf("predicate function is not a func(T) bool") - } - v, t := reflect.ValueOf(got), ftype.In(0) - if !v.IsValid() { - if !canBeNil(t.Kind()) { - note("predicate function", predicate) - return BadCheckf("cannot use nil as type %v in argument to predicate function", t) - } - v = reflect.Zero(t) - } else if !v.Type().AssignableTo(t) { - note("arg", got) - note("predicate function", predicate) - return BadCheckf("cannot use value of type %v as type %v in argument to predicate function", v.Type(), t) - } - if f.Call([]reflect.Value{v})[0].Interface().(bool) { - return nil - } - return fmt.Errorf("value does not satisfy predicate function") -} - -// IsTrue is a Checker checking that the provided value is true. -// The value must have a boolean underlying type. -// -// For instance: -// -// c.Assert(true, qt.IsTrue) -// c.Assert(myBoolean(false), qt.IsTrue) -var IsTrue Checker = &boolChecker{ - want: true, -} - -// IsFalse is a Checker checking that the provided value is false. -// The value must have a boolean underlying type. -// -// For instance: -// -// c.Assert(false, qt.IsFalse) -// c.Assert(IsValid(), qt.IsFalse) -var IsFalse Checker = &boolChecker{ - want: false, -} - -type boolChecker struct { - want bool -} - -// Check implements Checker.Check by checking that got == c.want. -func (c *boolChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - v := reflect.ValueOf(got) - if v.IsValid() && v.Kind() == reflect.Bool { - if v.Bool() != c.want { - return fmt.Errorf("value is not %v", c.want) - } - return nil - } - note("value", got) - return BadCheckf("value does not have a bool underlying type") -} - -// ArgNames implements Checker.ArgNames. -func (c *boolChecker) ArgNames() []string { - return []string{"got"} -} - -// Not returns a Checker negating the given Checker. -// -// For instance: -// -// c.Assert(got, qt.Not(qt.IsNil)) -// c.Assert(answer, qt.Not(qt.Equals), 42) -func Not(checker Checker) Checker { - return ¬Checker{ - Checker: checker, - } -} - -type notChecker struct { - Checker -} - -// Check implements Checker.Check by checking that the stored checker fails. -func (c *notChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - if nc, ok := c.Checker.(*notChecker); ok { - return nc.Checker.Check(got, args, note) - } - err = c.Checker.Check(got, args, note) - if IsBadCheck(err) { - return err - } - if err != nil { - return nil - } - if c.Checker == IsNil { - return errors.New("got nil value but want non-nil") - } - return errors.New("unexpected success") -} - -// Contains is a checker that checks that a map, slice, array -// or string contains a value. It's the same as using -// Any(Equals), except that it has a special case -// for strings - if the first argument is a string, -// the second argument must also be a string -// and strings.Contains will be used. -// -// For example: -// -// c.Assert("hello world", qt.Contains, "world") -// c.Assert([]int{3,5,7,99}, qt.Contains, 7) -var Contains Checker = &containsChecker{ - argNames: []string{"container", "want"}, -} - -type containsChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got contains args[0]. -func (c *containsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - if got, ok := got.(string); ok { - want, ok := args[0].(string) - if !ok { - return BadCheckf("strings can only contain strings, not %T", args[0]) - } - if strings.Contains(got, want) { - return nil - } - return errors.New("no substring match found") - } - return Any(Equals).Check(got, args, note) -} - -// Any returns a Checker that uses the given checker to check elements -// of a slice or array or the values from a map. It succeeds if any element -// passes the check. -// -// For example: -// -// c.Assert([]int{3,5,7,99}, qt.Any(qt.Equals), 7) -// c.Assert([][]string{{"a", "b"}, {"c", "d"}}, qt.Any(qt.DeepEquals), []string{"c", "d"}) -// -// See also All and Contains. -func Any(c Checker) Checker { - return &anyChecker{ - argNames: append([]string{"container"}, c.ArgNames()[1:]...), - elemChecker: c, - } -} - -type anyChecker struct { - argNames - elemChecker Checker -} - -// Check implements Checker.Check by checking that one of the elements of -// got passes the c.elemChecker check. -func (c *anyChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - iter, err := newIter(got) - if err != nil { - return BadCheckf("%v", err) - } - for iter.next() { - // For the time being, discard the notes added by the sub-checker, - // because it's not clear what a good behaviour would be. - // Should we print all the failed check for all elements? If there's only - // one element in the container, the answer is probably yes, - // but let's leave it for now. - err := c.elemChecker.Check( - iter.value().Interface(), - args, - func(key string, value interface{}) {}, - ) - if err == nil { - return nil - } - if IsBadCheck(err) { - return BadCheckf("at %s: %v", iter.key(), err) - } - } - return errors.New("no matching element found") -} - -// All returns a Checker that uses the given checker to check elements -// of slice or array or the values of a map. It succeeds if all elements -// pass the check. -// On failure it prints the error from the first index that failed. -// -// For example: -// -// c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0) -// c.Assert([][]string{{"a", "b"}, {"a", "b"}}, qt.All(qt.DeepEquals), []string{"c", "d"}) -// -// See also Any and Contains. -func All(c Checker) Checker { - return &allChecker{ - argNames: append([]string{"container"}, c.ArgNames()[1:]...), - elemChecker: c, - } -} - -type allChecker struct { - argNames - elemChecker Checker -} - -// Check implement Checker.Check by checking that all the elements of got -// pass the c.elemChecker check. -func (c *allChecker) Check(got interface{}, args []interface{}, notef func(key string, value interface{})) error { - iter, err := newIter(got) - if err != nil { - return BadCheckf("%v", err) - } - for iter.next() { - // Store any notes added by the checker so - // we can add our own note at the start - // to say which element failed. - var notes []note - err := c.elemChecker.Check( - iter.value().Interface(), - args, - func(key string, val interface{}) { - notes = append(notes, note{key, val}) - }, - ) - if err == nil { - continue - } - if IsBadCheck(err) { - return BadCheckf("at %s: %v", iter.key(), err) - } - notef("error", Unquoted("mismatch at "+iter.key())) - if err != ErrSilent { - // If the error's not silent, the checker is expecting - // the caller to print the error and the value that failed. - notef("error", Unquoted(err.Error())) - notef("first mismatched element", iter.value().Interface()) - } - for _, n := range notes { - notef(n.key, n.value) - } - return ErrSilent - } - return nil -} - -// JSONEquals is a checker that checks whether a byte slice -// or string is JSON-equivalent to a Go value. See CodecEquals for -// more information. -// -// It uses DeepEquals to do the comparison. If a more sophisticated -// comparison is required, use CodecEquals directly. -// -// For instance: -// -// c.Assert(`{"First": 47.11}`, qt.JSONEquals, &MyStruct{First: 47.11}) -var JSONEquals = CodecEquals(json.Marshal, json.Unmarshal) - -type codecEqualChecker struct { - argNames - marshal func(interface{}) ([]byte, error) - unmarshal func([]byte, interface{}) error - deepEquals Checker -} - -// CodecEquals returns a checker that checks for codec value equivalence. -// -// It expects two arguments: a byte slice or a string containing some -// codec-marshaled data, and a Go value. -// -// It uses unmarshal to unmarshal the data into an interface{} value. -// It marshals the Go value using marshal, then unmarshals the result into -// an interface{} value. -// -// It then checks that the two interface{} values are deep-equal to one -// another, using CmpEquals(opts) to perform the check. -// -// See JSONEquals for an example of this in use. -func CodecEquals( - marshal func(interface{}) ([]byte, error), - unmarshal func([]byte, interface{}) error, - opts ...cmp.Option, -) Checker { - return &codecEqualChecker{ - argNames: argNames{"got", "want"}, - marshal: marshal, - unmarshal: unmarshal, - deepEquals: CmpEquals(opts...), - } -} - -func (c *codecEqualChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - var gotContent []byte - switch got := got.(type) { - case string: - gotContent = []byte(got) - case []byte: - gotContent = got - default: - return BadCheckf("expected string or byte, got %T", got) - } - wantContent := args[0] - wantContentBytes, err := c.marshal(wantContent) - if err != nil { - return BadCheckf("cannot marshal expected contents: %v", err) - } - var wantContentVal interface{} - if err := c.unmarshal(wantContentBytes, &wantContentVal); err != nil { - return BadCheckf("cannot unmarshal expected contents: %v", err) - } - var gotContentVal interface{} - if err := c.unmarshal([]byte(gotContent), &gotContentVal); err != nil { - return fmt.Errorf("cannot unmarshal obtained contents: %v; %q", err, gotContent) - } - return c.deepEquals.Check(gotContentVal, []interface{}{wantContentVal}, note) -} - -// argNames helps implementing Checker.ArgNames. -type argNames []string - -// ArgNames implements Checker.ArgNames by returning the argument names. -func (a argNames) ArgNames() []string { - return a -} - -// match checks that the given error message matches the given pattern. -func match(got string, pattern interface{}, msg string, note func(key string, value interface{})) error { - if actualRegex, ok := pattern.(*regexp.Regexp); ok { - if actualRegex.MatchString(got) { - return nil - } - return errors.New(msg) - } - regex, ok := pattern.(string) - if !ok { - note("regexp", pattern) - return BadCheckf("regexp is not a string") - } - matches, err := regexp.MatchString("^("+regex+")$", got) - if err != nil { - note("regexp", regex) - return BadCheckf("cannot compile regexp: %s", err) - } - if matches { - return nil - } - return errors.New(msg) -} - -// canBeNil reports whether a value or type of the given kind can be nil. -func canBeNil(k reflect.Kind) bool { - switch k { - case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - return true - } - return false -} diff --git a/pkg/quicktest/checker_err.go b/pkg/quicktest/checker_err.go deleted file mode 100644 index 5033cefe..00000000 --- a/pkg/quicktest/checker_err.go +++ /dev/null @@ -1,92 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "errors" - "fmt" -) - -// ErrorAs checks that the error is or wraps a specific error type. If so, it -// assigns it to the provided pointer. This is analogous to calling errors.As. -// -// For instance: -// -// // Checking for a specific error type -// c.Assert(err, qt.ErrorAs, new(*os.PathError)) -// -// // Checking fields on a specific error type -// var pathError *os.PathError -// if c.Check(err, qt.ErrorAs, &pathError) { -// c.Assert(pathError.Path, qt.Equals, "some_path") -// } -var ErrorAs Checker = &errorAsChecker{ - argNames: []string{"got", "as"}, -} - -type errorAsChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is an error whose error -// chain matches args[0] and assigning it to args[0]. -func (c *errorAsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) (err error) { - if err := checkFirstArgIsError(got, note); err != nil { - return err - } - - gotErr := got.(error) - defer func() { - // A panic is raised when the target is not a pointer to an interface - // or error. - if r := recover(); r != nil { - err = BadCheckf("%s", r) - } - }() - as := args[0] - if errors.As(gotErr, as) { - return nil - } - - note("error", Unquoted("wanted type is not found in error chain")) - note("got", gotErr) - note("as", Unquoted(fmt.Sprintf("%T", as))) - return ErrSilent -} - -// ErrorIs checks that the error is or wraps a specific error value. This is -// analogous to calling errors.Is. -// -// For instance: -// -// c.Assert(err, qt.ErrorIs, os.ErrNotExist) -var ErrorIs Checker = &errorIsChecker{ - argNames: []string{"got", "want"}, -} - -type errorIsChecker struct { - argNames -} - -// Check implements Checker.Check by checking that got is an error whose error -// chain matches args[0]. -func (c *errorIsChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - if got == nil && args[0] == nil { - return nil - } - if err := checkFirstArgIsError(got, note); err != nil { - return err - } - - gotErr := got.(error) - wantErr, ok := args[0].(error) - if !ok && args[0] != nil { - note("want", args[0]) - return BadCheckf("second argument is not an error") - } - - if !errors.Is(gotErr, wantErr) { - return errors.New("wanted error is not found in error chain") - } - return nil -} diff --git a/pkg/quicktest/checker_err_test.go b/pkg/quicktest/checker_err_test.go deleted file mode 100644 index ed4629ea..00000000 --- a/pkg/quicktest/checker_err_test.go +++ /dev/null @@ -1,249 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "errors" - "fmt" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func init() { - checkerTests = append(checkerTests, errorCheckerTests...) -} - -type errTarget struct { - msg string -} - -func (e *errTarget) Error() string { - return "ptr: " + e.msg -} - -type errTargetNonPtr struct { - msg string -} - -func (e errTargetNonPtr) Error() string { - return "non ptr: " + e.msg -} - -var targetErr = &errTarget{msg: "target"} - -var errorCheckerTests = []struct { - about string - checker qt.Checker - got interface{} - args []interface{} - verbose bool - expectedCheckFailure string - expectedNegateFailure string -}{{ - about: "ErrorAs: exact match", - checker: qt.ErrorAs, - got: targetErr, - args: []interface{}{new(*errTarget)}, - expectedNegateFailure: ` -error: - unexpected success -got: - e"ptr: target" -as: - &&quicktest_test.errTarget{msg:"target"} -`, -}, { - about: "ErrorAs: wrapped match", - checker: qt.ErrorAs, - got: fmt.Errorf("wrapped: %w", targetErr), - args: []interface{}{new(*errTarget)}, - expectedNegateFailure: ` -error: - unexpected success -got: - e"wrapped: ptr: target" -as: - &&quicktest_test.errTarget{msg:"target"} -`, -}, { - about: "ErrorAs: fails if nil error", - checker: qt.ErrorAs, - got: nil, - args: []interface{}{new(*errTarget)}, - expectedCheckFailure: ` -error: - got nil error but want non-nil -got: - nil -as: - &(*quicktest_test.errTarget)(nil) -`, -}, { - about: "ErrorAs: fails if mismatch", - checker: qt.ErrorAs, - got: errors.New("other error"), - args: []interface{}{new(*errTarget)}, - expectedCheckFailure: ` -error: - wanted type is not found in error chain -got: - e"other error" -as: - **quicktest_test.errTarget -`, -}, { - about: "ErrorAs: fails if mismatch with a non-pointer error implementation", - checker: qt.ErrorAs, - got: errors.New("other error"), - args: []interface{}{new(errTargetNonPtr)}, - expectedCheckFailure: ` -error: - wanted type is not found in error chain -got: - e"other error" -as: - *quicktest_test.errTargetNonPtr -`, -}, { - about: "ErrorAs: bad check if invalid error", - checker: qt.ErrorAs, - got: "not an error", - args: []interface{}{new(*errTarget)}, - expectedCheckFailure: ` -error: - bad check: first argument is not an error -got: - "not an error" -`, - expectedNegateFailure: ` -error: - bad check: first argument is not an error -got: - "not an error" -`, -}, { - about: "ErrorAs: bad check if invalid as", - checker: qt.ErrorAs, - got: targetErr, - args: []interface{}{&struct{}{}}, - expectedCheckFailure: ` -error: - bad check: errors: *target must be interface or implement error -`, - expectedNegateFailure: ` -error: - bad check: errors: *target must be interface or implement error -`, -}, { - about: "ErrorIs: nil to nil match", - checker: qt.ErrorIs, - got: nil, - args: []interface{}{nil}, - expectedNegateFailure: ` -error: - unexpected success -got: - nil -want: - -`, -}, { - about: "ErrorIs: non-nil to nil mismatch", - checker: qt.ErrorIs, - got: targetErr, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - wanted error is not found in error chain -got: - e"ptr: target" -want: - nil -`, -}, { - about: "ErrorIs: exact match", - checker: qt.ErrorIs, - got: targetErr, - args: []interface{}{targetErr}, - expectedNegateFailure: ` -error: - unexpected success -got: - e"ptr: target" -want: - -`, -}, { - about: "ErrorIs: wrapped match", - checker: qt.ErrorIs, - got: fmt.Errorf("wrapped: %w", targetErr), - args: []interface{}{targetErr}, - expectedNegateFailure: ` -error: - unexpected success -got: - e"wrapped: ptr: target" -want: - e"ptr: target" -`, -}, { - about: "ErrorIs: fails if nil error", - checker: qt.ErrorIs, - got: nil, - args: []interface{}{targetErr}, - expectedCheckFailure: ` -error: - got nil error but want non-nil -got: - nil -want: - e"ptr: target" -`, -}, { - about: "ErrorIs: fails if mismatch", - checker: qt.ErrorIs, - got: errors.New("other error"), - args: []interface{}{targetErr}, - expectedCheckFailure: ` -error: - wanted error is not found in error chain -got: - e"other error" -want: - e"ptr: target" -`, -}, { - about: "ErrorIs: bad check if invalid error", - checker: qt.ErrorIs, - got: "not an error", - args: []interface{}{targetErr}, - expectedCheckFailure: ` -error: - bad check: first argument is not an error -got: - "not an error" -`, - expectedNegateFailure: ` -error: - bad check: first argument is not an error -got: - "not an error" -`, -}, { - about: "ErrorIs: bad check if invalid error value", - checker: qt.ErrorIs, - got: targetErr, - args: []interface{}{"not an error"}, - expectedCheckFailure: ` -error: - bad check: second argument is not an error -want: - "not an error" -`, - expectedNegateFailure: ` -error: - bad check: second argument is not an error -want: - "not an error" -`, -}} diff --git a/pkg/quicktest/checker_test.go b/pkg/quicktest/checker_test.go deleted file mode 100644 index 4a8cc41c..00000000 --- a/pkg/quicktest/checker_test.go +++ /dev/null @@ -1,3110 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "bytes" - "encoding/json" - "errors" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "regexp" - "strings" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -// Fooer is an interface for testing. -type Fooer interface { - Foo() -} - -var ( - goTime = time.Date(2012, 3, 28, 0, 0, 0, 0, time.UTC) - chInt = func() chan int { - ch := make(chan int, 4) - ch <- 42 - ch <- 47 - return ch - }() - sameInts = cmpopts.SortSlices(func(x, y int) bool { - return x < y - }) - cmpEqualsGot = struct { - Strings []interface{} - Ints []int - }{ - Strings: []interface{}{"who", "dalek"}, - Ints: []int{42, 47}, - } - cmpEqualsWant = struct { - Strings []interface{} - Ints []int - }{ - Strings: []interface{}{"who", "dalek"}, - Ints: []int{42}, - } -) - -type InnerJSON struct { - First string - Second int `json:",omitempty" yaml:",omitempty"` - Third map[string]bool `json:",omitempty" yaml:",omitempty"` -} - -type OuterJSON struct { - First float64 - Second []*InnerJSON `json:"Last,omitempty" yaml:"last,omitempty"` -} - -type boolean bool - -var checkerTests = []struct { - about string - checker qt.Checker - got interface{} - args []interface{} - verbose bool - expectedCheckFailure string - expectedNegateFailure string -}{{ - about: "Equals: same values", - checker: qt.Equals, - got: 42, - args: []interface{}{42}, - expectedNegateFailure: ` -error: - unexpected success -got: - int(42) -want: - -`, -}, { - about: "Equals: different values", - checker: qt.Equals, - got: "42", - args: []interface{}{"47"}, - expectedCheckFailure: ` -error: - values are not equal -got: - "42" -want: - "47" -`, -}, { - about: "Equals: different strings with quotes", - checker: qt.Equals, - got: `string "foo"`, - args: []interface{}{`string "bar"`}, - expectedCheckFailure: tilde2bq(` -error: - values are not equal -got: - ~string "foo"~ -want: - ~string "bar"~ -`), -}, { - about: "Equals: same multiline strings", - checker: qt.Equals, - got: "a\nmultiline\nstring", - args: []interface{}{"a\nmultiline\nstring"}, - expectedNegateFailure: ` -error: - unexpected success -got: - "a\nmultiline\nstring" -want: - -`, -}, { - about: "Equals: different multi-line strings", - checker: qt.Equals, - got: "a\nlong\nmultiline\nstring", - args: []interface{}{"just\na\nlong\nmulti-line\nstring\n"}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not equal -line diff (-got +want): -%s -got: - "a\nlong\nmultiline\nstring" -want: - "just\na\nlong\nmulti-line\nstring\n" -`, diff([]string{"a\n", "long\n", "multiline\n", "string"}, []string{"just\n", "a\n", "long\n", "multi-line\n", "string\n", ""})), -}, { - about: "Equals: different single-line strings ending with newline", - checker: qt.Equals, - got: "foo\n", - args: []interface{}{"bar\n"}, - expectedCheckFailure: ` -error: - values are not equal -got: - "foo\n" -want: - "bar\n" -`, -}, { - about: "Equals: different strings starting with newline", - checker: qt.Equals, - got: "\nfoo", - args: []interface{}{"\nbar"}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not equal -line diff (-got +want): -%s -got: - "\nfoo" -want: - "\nbar" -`, diff([]string{"\n", "foo"}, []string{"\n", "bar"})), -}, { - about: "Equals: different types", - checker: qt.Equals, - got: 42, - args: []interface{}{"42"}, - expectedCheckFailure: ` -error: - values are not equal -got: - int(42) -want: - "42" -`, -}, { - about: "Equals: nil and nil", - checker: qt.Equals, - got: nil, - args: []interface{}{nil}, - expectedNegateFailure: ` -error: - unexpected success -got: - nil -want: - -`, -}, { - about: "Equals: error is not nil", - checker: qt.Equals, - got: errBadWolf, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - got non-nil error -got: - bad wolf - file:line -want: - nil -`, -}, { - about: "Equals: error is not nil: not formatted", - checker: qt.Equals, - got: &errTest{ - msg: "bad wolf", - }, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - got non-nil error -got: - e"bad wolf" -want: - nil -`, -}, { - about: "Equals: error does not guard against nil", - checker: qt.Equals, - got: (*errTest)(nil), - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - got non-nil error -got: - e -want: - nil -`, -}, { - about: "Equals: error is not nil: not formatted and with quotes", - checker: qt.Equals, - got: &errTest{ - msg: `failure: "bad wolf"`, - }, - args: []interface{}{nil}, - expectedCheckFailure: tilde2bq(` -error: - got non-nil error -got: - e~failure: "bad wolf"~ -want: - nil -`), -}, { - about: "Equals: different errors with same message", - checker: qt.Equals, - got: &errTest{ - msg: "bad wolf", - }, - args: []interface{}{errors.New("bad wolf")}, - expectedCheckFailure: ` -error: - values are not equal -got type: - *quicktest_test.errTest -want type: - *errors.errorString -got: - e"bad wolf" -want: - -`, -}, { - about: "Equals: different pointer errors with the same message", - checker: qt.Equals, - got: &errTest{ - msg: "bad wolf", - }, - args: []interface{}{&errTest{ - msg: "bad wolf", - }}, - expectedCheckFailure: ` -error: - values are not equal -got: - e"bad wolf" -want: - -`, -}, { - about: "Equals: different pointers with the same formatted output", - checker: qt.Equals, - got: new(int), - args: []interface{}{new(int)}, - expectedCheckFailure: ` -error: - values are not equal -got: - &int(0) -want: - -`, -}, { - about: "Equals: nil struct", - checker: qt.Equals, - got: (*struct{})(nil), - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - values are not equal -got: - (*struct {})(nil) -want: - nil -`, -}, { - about: "Equals: different booleans", - checker: qt.Equals, - got: true, - args: []interface{}{false}, - expectedCheckFailure: ` -error: - values are not equal -got: - bool(true) -want: - bool(false) -`, -}, { - about: "Equals: uncomparable types", - checker: qt.Equals, - got: struct { - Ints []int - }{ - Ints: []int{42, 47}, - }, - args: []interface{}{struct { - Ints []int - }{ - Ints: []int{42, 47}, - }}, - expectedCheckFailure: ` -error: - runtime error: comparing uncomparable type struct { Ints []int } -got: - struct { Ints []int }{ - Ints: {42, 47}, - } -want: - -`, -}, { - about: "Equals: not enough arguments", - checker: qt.Equals, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, -}, { - about: "Equals: too many arguments", - checker: qt.Equals, - args: []interface{}{nil, 47}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - nil, - int(47), - } -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - nil, - int(47), - } -want args: - want -`, -}, { - about: "CmpEquals: same values", - checker: qt.CmpEquals(), - got: cmpEqualsGot, - args: []interface{}{cmpEqualsGot}, - expectedNegateFailure: ` -error: - unexpected success -got: - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - } -want: - -`, -}, { - about: "CmpEquals: different values", - checker: qt.CmpEquals(), - got: cmpEqualsGot, - args: []interface{}{cmpEqualsWant}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - } -want: - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - } -`, diff(cmpEqualsGot, cmpEqualsWant)), -}, { - about: "CmpEquals: different values, long output", - checker: qt.CmpEquals(), - got: []interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line 3"}, - args: []interface{}{[]interface{}{cmpEqualsWant, "extra line 1"}}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - -want: - []interface {}{ - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - "extra line 1", - } -`, diff([]interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line 3"}, []interface{}{cmpEqualsWant, "extra line 1"})), -}, { - about: "CmpEquals: different values: long output and verbose", - checker: qt.CmpEquals(), - got: []interface{}{cmpEqualsWant, "extra line 1", "extra line 2"}, - args: []interface{}{[]interface{}{cmpEqualsWant, "extra line 1"}}, - verbose: true, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - []interface {}{ - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - "extra line 1", - "extra line 2", - } -want: - []interface {}{ - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - "extra line 1", - } -`, diff([]interface{}{cmpEqualsWant, "extra line 1", "extra line 2"}, []interface{}{cmpEqualsWant, "extra line 1"})), -}, { - about: "CmpEquals: different values, long output, same number of lines", - checker: qt.CmpEquals(), - got: []interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line 3"}, - args: []interface{}{[]interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line three"}}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - -want: - -`, diff([]interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line 3"}, []interface{}{cmpEqualsWant, "extra line 1", "extra line 2", "extra line three"})), -}, { - about: "CmpEquals: same values with options", - checker: qt.CmpEquals(sameInts), - got: []int{1, 2, 3}, - args: []interface{}{ - []int{3, 2, 1}, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - []int{1, 2, 3} -want: - []int{3, 2, 1} -`, -}, { - about: "CmpEquals: different values with options", - checker: qt.CmpEquals(sameInts), - got: []int{1, 2, 4}, - args: []interface{}{ - []int{3, 2, 1}, - }, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - []int{1, 2, 4} -want: - []int{3, 2, 1} -`, diff([]int{1, 2, 4}, []int{3, 2, 1}, sameInts)), -}, { - about: "CmpEquals: structs with unexported fields not allowed", - checker: qt.CmpEquals(), - got: struct{ answer int }{ - answer: 42, - }, - args: []interface{}{ - struct{ answer int }{ - answer: 42, - }, - }, - expectedCheckFailure: ` -error: - bad check: cannot handle unexported field at root.answer: - "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest_test".(struct { answer int }) - consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported -`, - expectedNegateFailure: ` -error: - bad check: cannot handle unexported field at root.answer: - "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest_test".(struct { answer int }) - consider using a custom Comparer; if you control the implementation of type, you can also consider using an Exporter, AllowUnexported, or cmpopts.IgnoreUnexported -`, -}, { - about: "CmpEquals: structs with unexported fields ignored", - checker: qt.CmpEquals(cmpopts.IgnoreUnexported(struct{ answer int }{})), - got: struct{ answer int }{ - answer: 42, - }, - args: []interface{}{ - struct{ answer int }{ - answer: 42, - }, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - struct { answer int }{answer:42} -want: - -`, -}, { - about: "CmpEquals: same times", - checker: qt.CmpEquals(), - got: goTime, - args: []interface{}{ - goTime, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - s"2012-03-28 00:00:00 +0000 UTC" -want: - -`, -}, { - about: "CmpEquals: different times: verbose", - checker: qt.CmpEquals(), - got: goTime.Add(24 * time.Hour), - args: []interface{}{ - goTime, - }, - verbose: true, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - s"2012-03-29 00:00:00 +0000 UTC" -want: - s"2012-03-28 00:00:00 +0000 UTC" -`, diff(goTime.Add(24*time.Hour), goTime)), -}, { - about: "CmpEquals: not enough arguments", - checker: qt.CmpEquals(), - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, -}, { - about: "CmpEquals: too many arguments", - checker: qt.CmpEquals(), - got: []int{42}, - args: []interface{}{[]int{42}, "bad wolf"}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - []int{42}, - "bad wolf", - } -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - []int{42}, - "bad wolf", - } -want args: - want -`, -}, { - about: "DeepEquals: different values", - checker: qt.DeepEquals, - got: cmpEqualsGot, - args: []interface{}{cmpEqualsWant}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - } -want: - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - } -`, diff(cmpEqualsGot, cmpEqualsWant)), -}, { - about: "DeepEquals: different values: long output", - checker: qt.DeepEquals, - got: []interface{}{cmpEqualsWant, cmpEqualsWant}, - args: []interface{}{[]interface{}{cmpEqualsWant, cmpEqualsWant, 42}}, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - -want: - -`, diff([]interface{}{cmpEqualsWant, cmpEqualsWant}, []interface{}{cmpEqualsWant, cmpEqualsWant, 42})), -}, { - about: "DeepEquals: different values: long output and verbose", - checker: qt.DeepEquals, - got: []interface{}{cmpEqualsWant, cmpEqualsWant}, - args: []interface{}{[]interface{}{cmpEqualsWant, cmpEqualsWant, 42}}, - verbose: true, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - []interface {}{ - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - } -want: - []interface {}{ - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - struct { Strings []interface {}; Ints []int }{ - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - int(42), - } -`, diff([]interface{}{cmpEqualsWant, cmpEqualsWant}, []interface{}{cmpEqualsWant, cmpEqualsWant, 42})), -}, { - about: "ContentEquals: same values", - checker: qt.ContentEquals, - got: []string{"these", "are", "the", "voyages"}, - args: []interface{}{ - []string{"these", "are", "the", "voyages"}, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - []string{"these", "are", "the", "voyages"} -want: - -`, -}, { - about: "ContentEquals: same contents", - checker: qt.ContentEquals, - got: []int{1, 2, 3}, - args: []interface{}{ - []int{3, 2, 1}, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - []int{1, 2, 3} -want: - []int{3, 2, 1} -`, -}, { - about: "ContentEquals: same contents on complex slice", - checker: qt.ContentEquals, - got: []struct { - Strings []interface{} - Ints []int - }{cmpEqualsGot, cmpEqualsGot, cmpEqualsWant}, - args: []interface{}{ - []struct { - Strings []interface{} - Ints []int - }{cmpEqualsWant, cmpEqualsGot, cmpEqualsGot}, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - []struct { Strings []interface {}; Ints []int }{ - { - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - }, - { - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - }, - { - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - } -want: - []struct { Strings []interface {}; Ints []int }{ - { - Strings: { - "who", - "dalek", - }, - Ints: {42}, - }, - { - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - }, - { - Strings: { - "who", - "dalek", - }, - Ints: {42, 47}, - }, - } -`, -}, { - about: "ContentEquals: same contents on a nested slice", - checker: qt.ContentEquals, - got: struct { - Nums []int - }{ - Nums: []int{1, 2, 3, 4}, - }, - args: []interface{}{ - struct { - Nums []int - }{ - Nums: []int{4, 3, 2, 1}, - }, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - struct { Nums []int }{ - Nums: {1, 2, 3, 4}, - } -want: - struct { Nums []int }{ - Nums: {4, 3, 2, 1}, - } -`, -}, { - about: "ContentEquals: slices of different type", - checker: qt.ContentEquals, - got: []string{"bad", "wolf"}, - args: []interface{}{ - []interface{}{"bad", "wolf"}, - }, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - []string{"bad", "wolf"} -want: - []interface {}{ - "bad", - "wolf", - } -`, diff([]string{"bad", "wolf"}, []interface{}{"bad", "wolf"})), -}, { - about: "ContentEquals: not enough arguments", - checker: qt.ContentEquals, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, -}, { - about: "ContentEquals: too many arguments", - checker: qt.ContentEquals, - args: []interface{}{nil, nil}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - nil, - nil, - } -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - nil, - nil, - } -want args: - want -`, -}, { - about: "Matches: perfect match", - checker: qt.Matches, - got: "exterminate", - args: []interface{}{"exterminate"}, - expectedNegateFailure: ` -error: - unexpected success -got value: - "exterminate" -regexp: - -`, -}, { - about: "Matches: match", - checker: qt.Matches, - got: "these are the voyages", - args: []interface{}{"these are the .*"}, - expectedNegateFailure: ` -error: - unexpected success -got value: - "these are the voyages" -regexp: - "these are the .*" -`, -}, { - about: "Matches: match with pre-compiled regexp", - checker: qt.Matches, - got: bytes.NewBufferString("resistance is futile"), - args: []interface{}{regexp.MustCompile("resistance is (futile|useful)")}, - expectedNegateFailure: ` -error: - unexpected success -got value: - s"resistance is futile" -regexp: - s"resistance is (futile|useful)" -`, -}, { - about: "Matches: mismatch with pre-compiled regexp", - checker: qt.Matches, - got: bytes.NewBufferString("resistance is cool"), - args: []interface{}{regexp.MustCompile("resistance is (futile|useful)")}, - expectedCheckFailure: ` -error: - value.String() does not match regexp -got value: - s"resistance is cool" -regexp: - s"resistance is (futile|useful)" -`, -}, { - about: "Matches: match with pre-compiled multi-line regexp", - checker: qt.Matches, - got: bytes.NewBufferString("line 1\nline 2"), - args: []interface{}{regexp.MustCompile(`line \d\nline \d`)}, - expectedNegateFailure: ` -error: - unexpected success -got value: - s"line 1\nline 2" -regexp: - s"line \\d\\nline \\d" -`, -}, { - about: "Matches: match with stringer", - checker: qt.Matches, - got: bytes.NewBufferString("resistance is futile"), - args: []interface{}{"resistance is (futile|useful)"}, - expectedNegateFailure: ` -error: - unexpected success -got value: - s"resistance is futile" -regexp: - "resistance is (futile|useful)" -`, -}, { - about: "Matches: mismatch", - checker: qt.Matches, - got: "voyages", - args: []interface{}{"these are the voyages"}, - expectedCheckFailure: ` -error: - value does not match regexp -got value: - "voyages" -regexp: - "these are the voyages" -`, -}, { - about: "Matches: mismatch with stringer", - checker: qt.Matches, - got: bytes.NewBufferString("voyages"), - args: []interface{}{"these are the voyages"}, - expectedCheckFailure: ` -error: - value.String() does not match regexp -got value: - s"voyages" -regexp: - "these are the voyages" -`, -}, { - about: "Matches: empty pattern", - checker: qt.Matches, - got: "these are the voyages", - args: []interface{}{""}, - expectedCheckFailure: ` -error: - value does not match regexp -got value: - "these are the voyages" -regexp: - "" -`, -}, { - about: "Matches: complex pattern", - checker: qt.Matches, - got: "end of the universe", - args: []interface{}{"bad wolf|end of the .*"}, - expectedNegateFailure: ` -error: - unexpected success -got value: - "end of the universe" -regexp: - "bad wolf|end of the .*" -`, -}, { - about: "Matches: invalid pattern", - checker: qt.Matches, - got: "voyages", - args: []interface{}{"("}, - expectedCheckFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -regexp: - "(" -`, - expectedNegateFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -regexp: - "(" -`, -}, { - about: "Matches: pattern not a string", - checker: qt.Matches, - got: "", - args: []interface{}{[]int{42}}, - expectedCheckFailure: ` -error: - bad check: regexp is not a string -regexp: - []int{42} -`, - expectedNegateFailure: ` -error: - bad check: regexp is not a string -regexp: - []int{42} -`, -}, { - about: "Matches: not a string or as stringer", - checker: qt.Matches, - got: 42, - args: []interface{}{".*"}, - expectedCheckFailure: ` -error: - bad check: value is not a string or a fmt.Stringer -value: - int(42) -`, - expectedNegateFailure: ` -error: - bad check: value is not a string or a fmt.Stringer -value: - int(42) -`, -}, { - about: "Matches: not enough arguments", - checker: qt.Matches, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, -}, { - about: "Matches: too many arguments", - checker: qt.Matches, - got: "these are the voyages", - args: []interface{}{"these are the .*", nil}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "these are the .*", - nil, - } -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "these are the .*", - nil, - } -want args: - regexp -`, -}, { - about: "ErrorMatches: perfect match", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"bad wolf"}, - expectedNegateFailure: ` -error: - unexpected success -got error: - bad wolf - file:line -regexp: - "bad wolf" -`, -}, { - about: "ErrorMatches: match", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"bad .*"}, - expectedNegateFailure: ` -error: - unexpected success -got error: - bad wolf - file:line -regexp: - "bad .*" -`, -}, { - about: "ErrorMatches: mismatch", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"exterminate"}, - expectedCheckFailure: ` -error: - error does not match regexp -got error: - bad wolf - file:line -regexp: - "exterminate" -`, -}, { - about: "ErrorMatches: empty pattern", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{""}, - expectedCheckFailure: ` -error: - error does not match regexp -got error: - bad wolf - file:line -regexp: - "" -`, -}, { - about: "ErrorMatches: complex pattern", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"bad wolf|end of the universe"}, - expectedNegateFailure: ` -error: - unexpected success -got error: - bad wolf - file:line -regexp: - "bad wolf|end of the universe" -`, -}, { - about: "ErrorMatches: invalid pattern", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"("}, - expectedCheckFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -regexp: - "(" -`, - expectedNegateFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -regexp: - "(" -`, -}, { - about: "ErrorMatches: pattern not a string", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{[]int{42}}, - expectedCheckFailure: ` -error: - bad check: regexp is not a string -regexp: - []int{42} -`, - expectedNegateFailure: ` -error: - bad check: regexp is not a string -regexp: - []int{42} -`, -}, { - about: "ErrorMatches: not an error", - checker: qt.ErrorMatches, - got: 42, - args: []interface{}{".*"}, - expectedCheckFailure: ` -error: - bad check: first argument is not an error -got: - int(42) -`, - expectedNegateFailure: ` -error: - bad check: first argument is not an error -got: - int(42) -`, -}, { - about: "ErrorMatches: nil error", - checker: qt.ErrorMatches, - got: nil, - args: []interface{}{"some pattern"}, - expectedCheckFailure: ` -error: - got nil error but want non-nil -got error: - nil -regexp: - "some pattern" -`, -}, { - about: "ErrorMatches: not enough arguments", - checker: qt.ErrorMatches, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, -}, { - about: "ErrorMatches: too many arguments", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{"bad wolf", []string{"bad", "wolf"}}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "bad wolf", - []string{"bad", "wolf"}, - } -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "bad wolf", - []string{"bad", "wolf"}, - } -want args: - regexp -`, -}, { - about: "ErrorMatches: match with pre-compiled regexp", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{regexp.MustCompile("bad (wolf|dog)")}, - expectedNegateFailure: ` -error: - unexpected success -got error: - bad wolf - file:line -regexp: - s"bad (wolf|dog)" -`, -}, { - about: "ErrorMatches: match with pre-compiled multi-line regexp", - checker: qt.ErrorMatches, - got: errBadWolfMultiLine, - args: []interface{}{regexp.MustCompile(`bad (wolf|dog)\nfaulty (logic|statement)`)}, - expectedNegateFailure: ` -error: - unexpected success -got error: - bad wolf - faulty logic - file:line -regexp: - s"bad (wolf|dog)\\nfaulty (logic|statement)" -`, -}, { - about: "ErrorMatches: mismatch with pre-compiled regexp", - checker: qt.ErrorMatches, - got: errBadWolf, - args: []interface{}{regexp.MustCompile("good (wolf|dog)")}, - expectedCheckFailure: ` -error: - error does not match regexp -got error: - bad wolf - file:line -regexp: - s"good (wolf|dog)" -`, -}, { - about: "PanicMatches: perfect match", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{"error: bad wolf"}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - -`, -}, { - about: "PanicMatches: match", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{"error: .*"}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - "error: .*" -`, -}, { - about: "PanicMatches: mismatch", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{"error: exterminate"}, - expectedCheckFailure: ` -error: - panic value does not match regexp -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - "error: exterminate" -`, -}, { - about: "PanicMatches: empty pattern", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{""}, - expectedCheckFailure: ` -error: - panic value does not match regexp -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - "" -`, -}, { - about: "PanicMatches: complex pattern", - checker: qt.PanicMatches, - got: func() { panic("bad wolf") }, - args: []interface{}{"bad wolf|end of the universe"}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "bad wolf" -function: - func() {...} -regexp: - "bad wolf|end of the universe" -`, -}, { - about: "PanicMatches: invalid pattern", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{"("}, - expectedCheckFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -panic value: - "error: bad wolf" -regexp: - "(" -`, - expectedNegateFailure: ` -error: - bad check: cannot compile regexp: error parsing regexp: missing closing ): ` + "`^(()$`" + ` -panic value: - "error: bad wolf" -regexp: - "(" -`, -}, { - about: "PanicMatches: pattern not a string", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - bad check: regexp is not a string -panic value: - "error: bad wolf" -regexp: - nil -`, - expectedNegateFailure: ` -error: - bad check: regexp is not a string -panic value: - "error: bad wolf" -regexp: - nil -`, -}, { - about: "PanicMatches: match with pre-compiled regexp", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{regexp.MustCompile("error: bad (wolf|dog)")}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - s"error: bad (wolf|dog)" -`, -}, { - about: "PanicMatches: match with pre-compiled multi-line regexp", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf\nfaulty logic") }, - args: []interface{}{regexp.MustCompile(`error: bad (wolf|dog)\nfaulty (logic|statement)`)}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "error: bad wolf\nfaulty logic" -function: - func() {...} -regexp: - s"error: bad (wolf|dog)\\nfaulty (logic|statement)" -`, -}, { - about: "PanicMatches: mismatch with pre-compiled regexp", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{regexp.MustCompile("good (wolf|dog)")}, - expectedCheckFailure: ` -error: - panic value does not match regexp -panic value: - "error: bad wolf" -function: - func() {...} -regexp: - s"good (wolf|dog)" -`, -}, { - about: "PanicMatches: not a function", - checker: qt.PanicMatches, - got: map[string]int{"answer": 42}, - args: []interface{}{".*"}, - expectedCheckFailure: ` -error: - bad check: first argument is not a function -got: - map[string]int{"answer":42} -`, - expectedNegateFailure: ` -error: - bad check: first argument is not a function -got: - map[string]int{"answer":42} -`, -}, { - about: "PanicMatches: not a proper function", - checker: qt.PanicMatches, - got: func(int) { panic("error: bad wolf") }, - args: []interface{}{".*"}, - expectedCheckFailure: ` -error: - bad check: cannot use a function receiving arguments -function: - func(int) {...} -`, - expectedNegateFailure: ` -error: - bad check: cannot use a function receiving arguments -function: - func(int) {...} -`, -}, { - about: "PanicMatches: function returning something", - checker: qt.PanicMatches, - got: func() error { panic("error: bad wolf") }, - args: []interface{}{".*"}, - expectedNegateFailure: ` -error: - unexpected success -panic value: - "error: bad wolf" -function: - func() error {...} -regexp: - ".*" -`, -}, { - about: "PanicMatches: no panic", - checker: qt.PanicMatches, - got: func() {}, - args: []interface{}{".*"}, - expectedCheckFailure: ` -error: - function did not panic -function: - func() {...} -regexp: - ".*" -`, -}, { - about: "PanicMatches: not enough arguments", - checker: qt.PanicMatches, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, -}, { - about: "PanicMatches: too many arguments", - checker: qt.PanicMatches, - got: func() { panic("error: bad wolf") }, - args: []interface{}{"error: bad wolf", 42}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "error: bad wolf", - int(42), - } -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - "error: bad wolf", - int(42), - } -want args: - regexp -`, -}, { - about: "IsNil: nil", - checker: qt.IsNil, - got: nil, - expectedNegateFailure: ` -error: - got nil value but want non-nil -got: - nil -`, -}, { - about: "IsNil: nil struct", - checker: qt.IsNil, - got: (*struct{})(nil), - expectedNegateFailure: ` -error: - got nil value but want non-nil -got: - (*struct {})(nil) -`, -}, { - about: "IsNil: nil func", - checker: qt.IsNil, - got: (func())(nil), - expectedNegateFailure: ` -error: - got nil value but want non-nil -got: - func() {...} -`, -}, { - about: "IsNil: nil map", - checker: qt.IsNil, - got: (map[string]string)(nil), - expectedNegateFailure: ` -error: - got nil value but want non-nil -got: - map[string]string{} -`, -}, { - about: "IsNil: nil slice", - checker: qt.IsNil, - got: ([]int)(nil), - expectedNegateFailure: ` -error: - got nil value but want non-nil -got: - []int(nil) -`, -}, { - about: "IsNil: nil error-implementing type", - checker: qt.IsNil, - got: (*errTest)(nil), - expectedCheckFailure: ` -error: - error containing nil value of type *quicktest_test.errTest. See https://golang.org/doc/faq#nil_error -got: - e -`, -}, { - about: "IsNil: not nil", - checker: qt.IsNil, - got: 42, - expectedCheckFailure: ` -error: - got non-nil value -got: - int(42) -`, -}, { - about: "IsNil: error is not nil", - checker: qt.IsNil, - got: errBadWolf, - expectedCheckFailure: ` -error: - got non-nil error -got: - bad wolf - file:line -`, -}, { - about: "IsNil: too many arguments", - checker: qt.IsNil, - args: []interface{}{"not nil"}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - "not nil", - } -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - "not nil", - } -`, -}, { - about: "IsNotNil: success", - checker: qt.IsNotNil, - got: 42, - expectedNegateFailure: ` -error: - got non-nil value -got: - int(42) -`, -}, { - about: "IsNotNil: failure", - checker: qt.IsNotNil, - got: nil, - expectedCheckFailure: ` -error: - got nil value but want non-nil -got: - nil -`, -}, { - about: "HasLen: arrays with the same length", - checker: qt.HasLen, - got: [4]string{"these", "are", "the", "voyages"}, - args: []interface{}{4}, - expectedNegateFailure: ` -error: - unexpected success -len(got): - int(4) -got: - [4]string{"these", "are", "the", "voyages"} -want length: - -`, -}, { - about: "HasLen: channels with the same length", - checker: qt.HasLen, - got: chInt, - args: []interface{}{2}, - expectedNegateFailure: fmt.Sprintf(` -error: - unexpected success -len(got): - int(2) -got: - (chan int)(%v) -want length: - -`, chInt), -}, { - about: "HasLen: maps with the same length", - checker: qt.HasLen, - got: map[string]bool{"true": true}, - args: []interface{}{1}, - expectedNegateFailure: ` -error: - unexpected success -len(got): - int(1) -got: - map[string]bool{"true":true} -want length: - -`, -}, { - about: "HasLen: slices with the same length", - checker: qt.HasLen, - got: []int{}, - args: []interface{}{0}, - expectedNegateFailure: ` -error: - unexpected success -len(got): - int(0) -got: - []int{} -want length: - -`, -}, { - about: "HasLen: strings with the same length", - checker: qt.HasLen, - got: "these are the voyages", - args: []interface{}{21}, - expectedNegateFailure: ` -error: - unexpected success -len(got): - int(21) -got: - "these are the voyages" -want length: - -`, -}, { - about: "HasLen: arrays with different lengths", - checker: qt.HasLen, - got: [4]string{"these", "are", "the", "voyages"}, - args: []interface{}{0}, - expectedCheckFailure: ` -error: - unexpected length -len(got): - int(4) -got: - [4]string{"these", "are", "the", "voyages"} -want length: - int(0) -`, -}, { - about: "HasLen: channels with different lengths", - checker: qt.HasLen, - got: chInt, - args: []interface{}{4}, - expectedCheckFailure: fmt.Sprintf(` -error: - unexpected length -len(got): - int(2) -got: - (chan int)(%v) -want length: - int(4) -`, chInt), -}, { - about: "HasLen: maps with different lengths", - checker: qt.HasLen, - got: map[string]bool{"true": true}, - args: []interface{}{42}, - expectedCheckFailure: ` -error: - unexpected length -len(got): - int(1) -got: - map[string]bool{"true":true} -want length: - int(42) -`, -}, { - about: "HasLen: slices with different lengths", - checker: qt.HasLen, - got: []int{42, 47}, - args: []interface{}{1}, - expectedCheckFailure: ` -error: - unexpected length -len(got): - int(2) -got: - []int{42, 47} -want length: - int(1) -`, -}, { - about: "HasLen: strings with different lengths", - checker: qt.HasLen, - got: "these are the voyages", - args: []interface{}{42}, - expectedCheckFailure: ` -error: - unexpected length -len(got): - int(21) -got: - "these are the voyages" -want length: - int(42) -`, -}, { - about: "HasLen: value without a length", - checker: qt.HasLen, - got: 42, - args: []interface{}{42}, - expectedCheckFailure: ` -error: - bad check: first argument has no length -got: - int(42) -`, - expectedNegateFailure: ` -error: - bad check: first argument has no length -got: - int(42) -`, -}, { - about: "HasLen: expected value not a number", - checker: qt.HasLen, - got: "these are the voyages", - args: []interface{}{"bad wolf"}, - expectedCheckFailure: ` -error: - bad check: length is not an int -length: - "bad wolf" -`, - expectedNegateFailure: ` -error: - bad check: length is not an int -length: - "bad wolf" -`, -}, { - about: "HasLen: not enough arguments", - checker: qt.HasLen, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want length -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want length -`, -}, { - about: "HasLen: too many arguments", - checker: qt.HasLen, - got: []int{42}, - args: []interface{}{42, 47}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - int(42), - int(47), - } -want args: - want length -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - int(42), - int(47), - } -want args: - want length -`, -}, { - about: "Implements: implements interface", - checker: qt.Implements, - got: errBadWolf, - args: []interface{}{(*error)(nil)}, - expectedNegateFailure: ` -error: - unexpected success -got: - bad wolf - file:line -want interface pointer: - (*error)(nil) -`, -}, { - about: "Implements: does not implement interface", - checker: qt.Implements, - got: errBadWolf, - args: []interface{}{(*Fooer)(nil)}, - expectedCheckFailure: ` -error: - got value does not implement wanted interface -got: - bad wolf - file:line -want interface: - quicktest_test.Fooer -`, -}, { - about: "Implements: fails if got nil", - checker: qt.Implements, - got: nil, - args: []interface{}{(*Fooer)(nil)}, - expectedCheckFailure: ` -error: - got nil value but want non-nil -got: - nil -`, -}, { - about: "Implements: bad check if wanted is nil", - checker: qt.Implements, - got: errBadWolf, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - bad check: want a pointer to an interface variable but nil was provided -`, - expectedNegateFailure: ` -error: - bad check: want a pointer to an interface variable but nil was provided -`, -}, { - about: "Implements: bad check if wanted is not pointer", - checker: qt.Implements, - got: errBadWolf, - args: []interface{}{struct{}{}}, - expectedCheckFailure: ` -error: - bad check: want a pointer to an interface variable but a non-pointer value was provided -want: - struct {} -`, - expectedNegateFailure: ` -error: - bad check: want a pointer to an interface variable but a non-pointer value was provided -want: - struct {} -`, -}, { - about: "Implements: bad check if wanted is not pointer to interface", - checker: qt.Implements, - got: errBadWolf, - args: []interface{}{(*struct{})(nil)}, - expectedCheckFailure: ` -error: - bad check: want a pointer to an interface variable but a pointer to a concrete type was provided -want pointer type: - struct {} -`, - expectedNegateFailure: ` -error: - bad check: want a pointer to an interface variable but a pointer to a concrete type was provided -want pointer type: - struct {} -`, -}, { - about: "Implements: bad check if wanted is a pointer to the empty interface", - checker: qt.Implements, - got: 42, - args: []interface{}{(*interface{})(nil)}, - expectedCheckFailure: ` -error: - bad check: all types implement the empty interface, want a pointer to a variable that isn't the empty interface -want pointer type: - interface {} -`, - expectedNegateFailure: ` -error: - bad check: all types implement the empty interface, want a pointer to a variable that isn't the empty interface -want pointer type: - interface {} -`, -}, { - about: "Satisfies: success with an error", - checker: qt.Satisfies, - got: qt.BadCheckf("bad wolf"), - args: []interface{}{qt.IsBadCheck}, - expectedNegateFailure: ` -error: - unexpected success -arg: - e"bad check: bad wolf" -predicate function: - func(error) bool {...} -`, -}, { - about: "Satisfies: success with an int", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func(v int) bool { return v == 42 }, - }, - expectedNegateFailure: ` -error: - unexpected success -arg: - int(42) -predicate function: - func(int) bool {...} -`, -}, { - about: "Satisfies: success with nil", - checker: qt.Satisfies, - got: nil, - args: []interface{}{ - func(v []int) bool { return true }, - }, - expectedNegateFailure: ` -error: - unexpected success -arg: - nil -predicate function: - func([]int) bool {...} -`, -}, { - about: "Satisfies: failure with an error", - checker: qt.Satisfies, - got: nil, - args: []interface{}{qt.IsBadCheck}, - expectedCheckFailure: ` -error: - value does not satisfy predicate function -arg: - nil -predicate function: - func(error) bool {...} -`, -}, { - about: "Satisfies: failure with a string", - checker: qt.Satisfies, - got: "bad wolf", - args: []interface{}{ - func(string) bool { return false }, - }, - expectedCheckFailure: ` -error: - value does not satisfy predicate function -arg: - "bad wolf" -predicate function: - func(string) bool {...} -`, -}, { - about: "Satisfies: not a function", - checker: qt.Satisfies, - got: 42, - args: []interface{}{42}, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - int(42) -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - int(42) -`, -}, { - about: "Satisfies: function accepting no arguments", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func() bool { return true }, - }, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func() bool {...} -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func() bool {...} -`, -}, { - about: "Satisfies: function accepting too many arguments", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func(int, string) bool { return false }, - }, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int, string) bool {...} -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int, string) bool {...} -`, -}, { - about: "Satisfies: function returning no arguments", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func(error) {}, - }, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(error) {...} -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(error) {...} -`, -}, { - about: "Satisfies: function returning too many argments", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func(int) (bool, error) { return true, nil }, - }, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int) (bool, error) {...} -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int) (bool, error) {...} -`, -}, { - about: "Satisfies: function not returning a bool", - checker: qt.Satisfies, - got: 42, - args: []interface{}{ - func(int) error { return nil }, - }, - expectedCheckFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int) error {...} -`, - expectedNegateFailure: ` -error: - bad check: predicate function is not a func(T) bool -predicate function: - func(int) error {...} -`, -}, { - about: "Satisfies: type mismatch", - checker: qt.Satisfies, - got: 42, - args: []interface{}{qt.IsBadCheck}, - expectedCheckFailure: ` -error: - bad check: cannot use value of type int as type error in argument to predicate function -arg: - int(42) -predicate function: - func(error) bool {...} -`, - expectedNegateFailure: ` -error: - bad check: cannot use value of type int as type error in argument to predicate function -arg: - int(42) -predicate function: - func(error) bool {...} -`, -}, { - about: "Satisfies: nil value that cannot be nil", - checker: qt.Satisfies, - got: nil, - args: []interface{}{ - func(string) bool { return true }, - }, - expectedCheckFailure: ` -error: - bad check: cannot use nil as type string in argument to predicate function -predicate function: - func(string) bool {...} -`, - expectedNegateFailure: ` -error: - bad check: cannot use nil as type string in argument to predicate function -predicate function: - func(string) bool {...} -`, -}, { - about: "Satisfies: not enough arguments", - checker: qt.Satisfies, - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - predicate function -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - predicate function -`, -}, { - about: "Satisfies: too many arguments", - checker: qt.Satisfies, - got: 42, - args: []interface{}{func() bool { return true }, 1, 2}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 3, want 1 -got args: - []interface {}{ - func() bool {...}, - int(1), - int(2), - } -want args: - predicate function -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 3, want 1 -got args: - []interface {}{ - func() bool {...}, - int(1), - int(2), - } -want args: - predicate function -`, -}, { - about: "IsTrue: success", - checker: qt.IsTrue, - got: true, - expectedNegateFailure: ` -error: - unexpected success -got: - bool(true) -`, -}, { - about: "IsTrue: failure", - checker: qt.IsTrue, - got: false, - expectedCheckFailure: ` -error: - value is not true -got: - bool(false) -`, -}, { - about: "IsTrue: success with subtype", - checker: qt.IsTrue, - got: boolean(true), - expectedNegateFailure: ` -error: - unexpected success -got: - quicktest_test.boolean(true) -`, -}, { - about: "IsTrue: failure with subtype", - checker: qt.IsTrue, - got: boolean(false), - expectedCheckFailure: ` -error: - value is not true -got: - quicktest_test.boolean(false) -`, -}, { - about: "IsTrue: nil value", - checker: qt.IsTrue, - got: nil, - expectedCheckFailure: ` -error: - bad check: value does not have a bool underlying type -value: - nil -`, - expectedNegateFailure: ` -error: - bad check: value does not have a bool underlying type -value: - nil -`, -}, { - about: "IsTrue: non-bool value", - checker: qt.IsTrue, - got: 42, - expectedCheckFailure: ` -error: - bad check: value does not have a bool underlying type -value: - int(42) -`, - expectedNegateFailure: ` -error: - bad check: value does not have a bool underlying type -value: - int(42) -`, -}, { - about: "IsFalse: success", - checker: qt.IsFalse, - got: false, - expectedNegateFailure: ` -error: - unexpected success -got: - bool(false) -`, -}, { - about: "IsFalse: failure", - checker: qt.IsFalse, - got: true, - expectedCheckFailure: ` -error: - value is not false -got: - bool(true) -`, -}, { - about: "IsFalse: success with subtype", - checker: qt.IsFalse, - got: boolean(false), - expectedNegateFailure: ` -error: - unexpected success -got: - quicktest_test.boolean(false) -`, -}, { - about: "IsFalse: failure with subtype", - checker: qt.IsFalse, - got: boolean(true), - expectedCheckFailure: ` -error: - value is not false -got: - quicktest_test.boolean(true) -`, -}, { - about: "IsFalse: nil value", - checker: qt.IsFalse, - got: nil, - expectedCheckFailure: ` -error: - bad check: value does not have a bool underlying type -value: - nil -`, - expectedNegateFailure: ` -error: - bad check: value does not have a bool underlying type -value: - nil -`, -}, { - about: "IsFalse: non-bool value", - checker: qt.IsFalse, - got: "bad wolf", - expectedCheckFailure: ` -error: - bad check: value does not have a bool underlying type -value: - "bad wolf" -`, - expectedNegateFailure: ` -error: - bad check: value does not have a bool underlying type -value: - "bad wolf" -`, -}, { - about: "Not: success", - checker: qt.Not(qt.IsNil), - got: 42, - expectedNegateFailure: ` -error: - got non-nil value -got: - int(42) -`, -}, { - about: "Not: failure", - checker: qt.Not(qt.Equals), - got: 42, - args: []interface{}{42}, - expectedCheckFailure: ` -error: - unexpected success -got: - int(42) -want: - -`, -}, { - about: "Not: IsNil failure", - checker: qt.Not(qt.IsNil), - got: nil, - expectedCheckFailure: ` -error: - got nil value but want non-nil -got: - nil -`, -}, { - about: "Not: not enough arguments", - checker: qt.Not(qt.PanicMatches), - expectedCheckFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, - expectedNegateFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - regexp -`, -}, { - about: "Not: too many arguments", - checker: qt.Not(qt.Equals), - args: []interface{}{42, nil}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - int(42), - nil, - } -want args: - want -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - int(42), - nil, - } -want args: - want -`, -}, { - about: "Contains with string", - checker: qt.Contains, - got: "hello, world", - args: []interface{}{"world"}, - expectedNegateFailure: ` -error: - unexpected success -container: - "hello, world" -want: - "world" -`, -}, { - about: "Contains with string no match", - checker: qt.Contains, - got: "hello, world", - args: []interface{}{"worlds"}, - expectedCheckFailure: ` -error: - no substring match found -container: - "hello, world" -want: - "worlds" -`, -}, { - about: "Contains with slice", - checker: qt.Contains, - got: []string{"a", "b", "c"}, - args: []interface{}{"a"}, - expectedNegateFailure: ` -error: - unexpected success -container: - []string{"a", "b", "c"} -want: - "a" -`, -}, { - about: "Contains with map", - checker: qt.Contains, - // Note: we can't use more than one element here because - // pretty.Print output is non-deterministic. - // https://github.com/kr/pretty/issues/47 - got: map[string]string{"a": "d"}, - args: []interface{}{"d"}, - expectedNegateFailure: ` -error: - unexpected success -container: - map[string]string{"a":"d"} -want: - "d" -`, -}, { - about: "Contains with non-string", - checker: qt.Contains, - got: "aa", - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: strings can only contain strings, not int -`, - expectedNegateFailure: ` -error: - bad check: strings can only contain strings, not int -`, -}, { - about: "All slice equals", - checker: qt.All(qt.Equals), - got: []string{"a", "a"}, - args: []interface{}{"a"}, - expectedNegateFailure: ` -error: - unexpected success -container: - []string{"a", "a"} -want: - "a" -`, -}, { - about: "All slice match", - checker: qt.All(qt.Matches), - got: []string{"red", "blue", "green"}, - args: []interface{}{".*e.*"}, - expectedNegateFailure: ` -error: - unexpected success -container: - []string{"red", "blue", "green"} -regexp: - ".*e.*" -`, -}, { - about: "All nested match", - checker: qt.All(qt.All(qt.Matches)), - got: [][]string{{"hello", "goodbye"}, {"red", "blue"}, {}}, - args: []interface{}{".*e.*"}, - expectedNegateFailure: ` -error: - unexpected success -container: - [][]string{ - {"hello", "goodbye"}, - {"red", "blue"}, - {}, - } -regexp: - ".*e.*" -`, -}, { - about: "All nested mismatch", - checker: qt.All(qt.All(qt.Matches)), - got: [][]string{{"hello", "goodbye"}, {"black", "blue"}, {}}, - args: []interface{}{".*e.*"}, - expectedCheckFailure: ` -error: - mismatch at index 1 -error: - mismatch at index 0 -error: - value does not match regexp -first mismatched element: - "black" -`, -}, { - about: "All slice mismatch", - checker: qt.All(qt.Matches), - got: []string{"red", "black"}, - args: []interface{}{".*e.*"}, - expectedCheckFailure: ` -error: - mismatch at index 1 -error: - value does not match regexp -first mismatched element: - "black" -`, -}, { - about: "All slice mismatch with DeepEqual", - checker: qt.All(qt.DeepEquals), - got: [][]string{{"a", "b"}, {"a", "c"}}, - args: []interface{}{[]string{"a", "b"}}, - expectedCheckFailure: fmt.Sprintf(` -error: - mismatch at index 1 -error: - values are not deep equal -diff (-got +want): -%s -got: - []string{"a", "c"} -want: - []string{"a", "b"} -`, diff([]string{"a", "c"}, []string{"a", "b"})), -}, { - about: "All bad checker args count", - checker: qt.All(qt.IsNil), - got: []int{}, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - int(5), - } -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - int(5), - } -`, -}, { - about: "All bad checker args", - checker: qt.All(qt.Matches), - got: []string{"hello"}, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: at index 0: bad check: regexp is not a string -`, - expectedNegateFailure: ` -error: - bad check: at index 0: bad check: regexp is not a string -`, -}, { - about: "All with non-container", - checker: qt.All(qt.Equals), - got: 5, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: map, slice or array required -`, - expectedNegateFailure: ` -error: - bad check: map, slice or array required -`, -}, { - about: "All mismatch with map", - checker: qt.All(qt.Matches), - got: map[string]string{"a": "red", "b": "black"}, - args: []interface{}{".*e.*"}, - expectedCheckFailure: ` -error: - mismatch at key "b" -error: - value does not match regexp -first mismatched element: - "black" -`, -}, { - about: "Any with non-container", - checker: qt.Any(qt.Equals), - got: 5, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: map, slice or array required -`, - expectedNegateFailure: ` -error: - bad check: map, slice or array required -`, -}, { - about: "Any no match", - checker: qt.Any(qt.Equals), - got: []int{}, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - no matching element found -container: - []int{} -want: - int(5) -`, -}, { - about: "Any bad checker arg count", - checker: qt.Any(qt.IsNil), - got: []int{}, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - int(5), - } -`, - expectedNegateFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -got args: - []interface {}{ - int(5), - } -`, -}, { - about: "Any bad checker args", - checker: qt.Any(qt.Matches), - got: []string{"hello"}, - args: []interface{}{5}, - expectedCheckFailure: ` -error: - bad check: at index 0: bad check: regexp is not a string -`, - expectedNegateFailure: ` -error: - bad check: at index 0: bad check: regexp is not a string -`, -}, { - about: "JSONEquals simple", - checker: qt.JSONEquals, - got: `{"First": 47.11}`, - args: []interface{}{ - &OuterJSON{ - First: 47.11, - }, - }, - expectedNegateFailure: tilde2bq(` -error: - unexpected success -got: - ~{"First": 47.11}~ -want: - &quicktest_test.OuterJSON{ - First: 47.11, - Second: nil, - } -`), -}, { - about: "JSONEquals nested", - checker: qt.JSONEquals, - got: `{"First": 47.11, "Last": [{"First": "Hello", "Second": 42}]}`, - args: []interface{}{ - &OuterJSON{ - First: 47.11, - Second: []*InnerJSON{ - {First: "Hello", Second: 42}, - }, - }, - }, - expectedNegateFailure: tilde2bq(` -error: - unexpected success -got: - ~{"First": 47.11, "Last": [{"First": "Hello", "Second": 42}]}~ -want: - &quicktest_test.OuterJSON{ - First: 47.11, - Second: { - &quicktest_test.InnerJSON{ - First: "Hello", - Second: 42, - Third: {}, - }, - }, - } -`), -}, { - about: "JSONEquals nested with newline", - checker: qt.JSONEquals, - got: `{"First": 47.11, "Last": [{"First": "Hello", "Second": 42}, - {"First": "World", "Third": {"F": false}}]}`, - args: []interface{}{ - &OuterJSON{ - First: 47.11, - Second: []*InnerJSON{ - {First: "Hello", Second: 42}, - {First: "World", Third: map[string]bool{ - "F": false, - }}, - }, - }, - }, - expectedNegateFailure: ` -error: - unexpected success -got: - "{\"First\": 47.11, \"Last\": [{\"First\": \"Hello\", \"Second\": 42},\n\t\t\t{\"First\": \"World\", \"Third\": {\"F\": false}}]}" -want: - &quicktest_test.OuterJSON{ - First: 47.11, - Second: { - &quicktest_test.InnerJSON{ - First: "Hello", - Second: 42, - Third: {}, - }, - &quicktest_test.InnerJSON{ - First: "World", - Second: 0, - Third: {"F":false}, - }, - }, - } -`, -}, { - about: "JSONEquals extra field", - checker: qt.JSONEquals, - got: `{"NotThere": 1}`, - args: []interface{}{ - &OuterJSON{ - First: 2, - }, - }, - expectedCheckFailure: fmt.Sprintf(` -error: - values are not deep equal -diff (-got +want): -%s -got: - map[string]interface {}{ - "NotThere": float64(1), - } -want: - map[string]interface {}{ - "First": float64(2), - } -`, diff(map[string]interface{}{"NotThere": 1.0}, map[string]interface{}{"First": 2.0})), -}, { - about: "JSONEquals cannot unmarshal obtained value", - checker: qt.JSONEquals, - got: `{"NotThere": `, - args: []interface{}{nil}, - expectedCheckFailure: fmt.Sprintf(tilde2bq(` -error: - cannot unmarshal obtained contents: %s; "{\"NotThere\": " -got: - ~{"NotThere": ~ -want: - nil -`), mustJSONUnmarshalErr(`{"NotThere": `)), -}, { - about: "JSONEquals cannot marshal expected value", - checker: qt.JSONEquals, - got: `null`, - args: []interface{}{ - jsonErrorMarshaler{}, - }, - expectedCheckFailure: ` -error: - bad check: cannot marshal expected contents: json: error calling MarshalJSON for type quicktest_test.jsonErrorMarshaler: qt json marshal error -`, - expectedNegateFailure: ` -error: - bad check: cannot marshal expected contents: json: error calling MarshalJSON for type quicktest_test.jsonErrorMarshaler: qt json marshal error -`, -}, { - about: "JSONEquals with []byte", - checker: qt.JSONEquals, - got: []byte("null"), - args: []interface{}{nil}, - expectedNegateFailure: ` -error: - unexpected success -got: - []uint8("null") -want: - nil -`, -}, { - about: "JSONEquals with RawMessage", - checker: qt.JSONEquals, - got: []byte("null"), - args: []interface{}{json.RawMessage("null")}, - expectedNegateFailure: ` -error: - unexpected success -got: - []uint8("null") -want: - json.RawMessage("null") -`, -}, { - about: "JSONEquals with bad type", - checker: qt.JSONEquals, - got: 0, - args: []interface{}{nil}, - expectedCheckFailure: ` -error: - bad check: expected string or byte, got int -`, - expectedNegateFailure: ` -error: - bad check: expected string or byte, got int -`, -}, { - about: "CodecEquals with bad marshal", - checker: qt.CodecEquals( - func(x interface{}) ([]byte, error) { return []byte("bad json"), nil }, - json.Unmarshal, - ), - got: "null", - args: []interface{}{nil}, - expectedCheckFailure: fmt.Sprintf(` -error: - bad check: cannot unmarshal expected contents: %s -`, mustJSONUnmarshalErr("bad json")), - expectedNegateFailure: fmt.Sprintf(` -error: - bad check: cannot unmarshal expected contents: %s -`, mustJSONUnmarshalErr("bad json")), -}, { - about: "CodecEquals with options", - checker: qt.CodecEquals( - json.Marshal, - json.Unmarshal, - cmpopts.SortSlices(func(x, y interface{}) bool { return x.(string) < y.(string) }), - ), - got: `["b", "z", "c", "a"]`, - args: []interface{}{[]string{"a", "c", "z", "b"}}, - expectedNegateFailure: tilde2bq(` -error: - unexpected success -got: - ~["b", "z", "c", "a"]~ -want: - []string{"a", "c", "z", "b"} -`), -}} - -func TestCheckers(t *testing.T) { - original := qt.TestingVerbose - defer func() { - qt.TestingVerbose = original - }() - for _, test := range checkerTests { - *qt.TestingVerbose = func() bool { - return test.verbose - } - - t.Run(test.about, func(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - ok := c.Check(test.got, test.checker, test.args...) - checkResult(t, ok, tt.errorString(), test.expectedCheckFailure) - }) - t.Run("Not "+test.about, func(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - ok := c.Check(test.got, qt.Not(test.checker), test.args...) - checkResult(t, ok, tt.errorString(), test.expectedNegateFailure) - }) - } -} - -func diff(x, y interface{}, opts ...cmp.Option) string { - d := cmp.Diff(x, y, opts...) - return strings.TrimSuffix(qt.Prefixf(" ", "%s", d), "\n") -} - -type jsonErrorMarshaler struct{} - -func (jsonErrorMarshaler) MarshalJSON() ([]byte, error) { - return nil, fmt.Errorf("qt json marshal error") -} - -func mustJSONUnmarshalErr(s string) error { - var v interface{} - err := json.Unmarshal([]byte(s), &v) - if err == nil { - panic("want JSON error, got nil") - } - return err -} - -func tilde2bq(s string) string { - return strings.Replace(s, "~", "`", -1) -} diff --git a/pkg/quicktest/cleanup_test.go b/pkg/quicktest/cleanup_test.go deleted file mode 100644 index 26380aa8..00000000 --- a/pkg/quicktest/cleanup_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build go1.14 -// +build go1.14 - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -// This file defines tests that are only valid since the Cleanup -// method was added in Go 1.14. - -func TestCCleanup(t *testing.T) { - c := qt.New(t) - cleanups := 0 - c.Run("defer", func(c *qt.C) { - c.Cleanup(func() { - cleanups++ - }) - }) - c.Assert(cleanups, qt.Equals, 1) -} - -func TestCDeferWithoutDone(t *testing.T) { - c := qt.New(t) - tc := &testingTWithCleanup{ - TB: t, - cleanup: func() {}, - } - c1 := qt.New(tc) - c1.Defer(func() {}) - c1.Defer(func() {}) - c.Assert(tc.cleanup, qt.PanicMatches, `Done not called after Defer`) -} - -func TestCDeferFromDefer(t *testing.T) { - c := qt.New(t) - tc := &testingTWithCleanup{ - TB: t, - cleanup: func() {}, - } - c1 := qt.New(tc) - c1.Defer(func() { - c1.Log("defer 1") - // This defer is triggered from the first Done(). - // It should have its own Done() call too. - c1.Defer(func() { - c1.Log("defer 2") - }) - }) - c1.Done() - // Check that we report the missing second Done(). - c.Assert(tc.cleanup, qt.PanicMatches, `Done not called after Defer`) -} - -func TestCDeferVsCleanupOrder(t *testing.T) { - c := qt.New(t) - var defers []int - c.Run("subtest", func(c *qt.C) { - c.Defer(func() { - defers = append(defers, 0) - }) - c.Cleanup(func() { - defers = append(defers, 1) - }) - c.Defer(func() { - defers = append(defers, 2) - }) - c.Cleanup(func() { - defers = append(defers, 3) - }) - }) - c.Assert(defers, qt.DeepEquals, []int{3, 2, 1, 0}) -} - -type testingTWithCleanup struct { - testing.TB - cleanup func() -} - -func (t *testingTWithCleanup) Cleanup(f func()) { - oldCleanup := t.cleanup - t.cleanup = func() { - defer oldCleanup() - f() - } -} diff --git a/pkg/quicktest/comment.go b/pkg/quicktest/comment.go deleted file mode 100644 index e9d72306..00000000 --- a/pkg/quicktest/comment.go +++ /dev/null @@ -1,31 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import "fmt" - -// Commentf returns a test comment whose output is formatted according to -// the given format specifier and args. It may be provided as the last argument -// to any check or assertion and will be displayed if the check or assertion -// fails. For instance: -// -// c.Assert(a, qt.Equals, 42, qt.Commentf("answer is not %d", 42)) -func Commentf(format string, args ...interface{}) Comment { - return Comment{ - format: format, - args: args, - } -} - -// Comment represents additional information on a check or an assertion which is -// displayed when the check or assertion fails. -type Comment struct { - format string - args []interface{} -} - -// String outputs a string formatted according to the stored format specifier -// and args. -func (c Comment) String() string { - return fmt.Sprintf(c.format, c.args...) -} diff --git a/pkg/quicktest/comment_test.go b/pkg/quicktest/comment_test.go deleted file mode 100644 index 9b66689d..00000000 --- a/pkg/quicktest/comment_test.go +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestCommentf(t *testing.T) { - c := qt.Commentf("the answer is %d", 42) - comment := c.String() - expectedComment := "the answer is 42" - if comment != expectedComment { - t.Fatalf("comment error:\ngot %q\nwant %q", comment, expectedComment) - } -} - -func TestConstantCommentf(t *testing.T) { - const expectedComment = "bad wolf" - c := qt.Commentf(expectedComment) - comment := c.String() - if comment != expectedComment { - t.Fatalf("constant comment error:\ngot %q\nwant %q", comment, expectedComment) - } -} diff --git a/pkg/quicktest/deferpanic_test.go b/pkg/quicktest/deferpanic_test.go deleted file mode 100644 index b79ef8d2..00000000 --- a/pkg/quicktest/deferpanic_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build !go1.14 -// +build !go1.14 - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestCDeferCalledEvenAfterDeferPanic(t *testing.T) { - // This test doesn't test anything useful under go 1.14 and - // later when Cleanup is built in. - c := qt.New(t) - deferred1 := 0 - deferred2 := 0 - c.Defer(func() { - deferred1++ - }) - c.Defer(func() { - panic("scream and shout") - }) - c.Defer(func() { - deferred2++ - }) - c.Defer(func() { - panic("run in circles") - }) - func() { - defer func() { - c.Check(recover(), qt.Equals, "scream and shout") - }() - c.Done() - }() - c.Assert(deferred1, qt.Equals, 1) - c.Assert(deferred2, qt.Equals, 1) - // Check that calling Done again doesn't panic. - c.Done() - c.Assert(deferred1, qt.Equals, 1) - c.Assert(deferred2, qt.Equals, 1) -} diff --git a/pkg/quicktest/doc.go b/pkg/quicktest/doc.go deleted file mode 100644 index fe50c961..00000000 --- a/pkg/quicktest/doc.go +++ /dev/null @@ -1,340 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -/* -Package quicktest provides a collection of Go helpers for writing tests. - -Quicktest helpers can be easily integrated inside regular Go tests, for -instance: - - import qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" - - func TestFoo(t *testing.T) { - t.Run("numbers", func(t *testing.T) { - c := qt.New(t) - numbers, err := somepackage.Numbers() - c.Assert(err, qt.IsNil) - c.Assert(numbers, qt.DeepEquals, []int{42, 47}) - }) - t.Run("bad wolf error", func(t *testing.T) { - c := qt.New(t) - numbers, err := somepackage.Numbers() - c.Assert(err, qt.ErrorMatches, "bad wolf") - }) - t.Run("nil", func(t *testing.T) { - c := qt.New(t) - got := somepackage.MaybeNil() - c.Assert(got, qt.IsNil, qt.Commentf("value: %v", somepackage.Value)) - }) - } - -# Assertions - -An assertion looks like this, where qt.Equals could be replaced by any -available checker. If the assertion fails, the underlying Fatal method is -called to describe the error and abort the test. - - c := qt.New(t) - c.Assert(someValue, qt.Equals, wantValue) - -If you don’t want to abort on failure, use Check instead, which calls Error -instead of Fatal: - - c.Check(someValue, qt.Equals, wantValue) - -For really short tests, the extra line for instantiating *qt.C can be avoided: - - qt.Assert(t, someValue, qt.Equals, wantValue) - qt.Check(t, someValue, qt.Equals, wantValue) - -The library provides some base checkers like Equals, DeepEquals, Matches, -ErrorMatches, IsNil and others. More can be added by implementing the Checker -interface. Below, we list the checkers implemented by the package in alphabetical -order. - -# All - -All returns a Checker that uses the given checker to check elements of slice or -array or the values of a map. It succeeds if all elements pass the check. -On failure it prints the error from the first index that failed. - -For example: - - c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0) - c.Assert([][]string{{"a", "b"}, {"a", "b"}}, qt.All(qt.DeepEquals), []string{"c", "d"}) - -See also Any and Contains. - -# Any - -Any returns a Checker that uses the given checker to check elements of a slice -or array or the values from a map. It succeeds if any element passes the check. - -For example: - - c.Assert([]int{3,5,7,99}, qt.Any(qt.Equals), 7) - c.Assert([][]string{{"a", "b"}, {"c", "d"}}, qt.Any(qt.DeepEquals), []string{"c", "d"}) - -See also All and Contains. - -# CmpEquals - -CmpEquals checks equality of two arbitrary values according to the provided -compare options. DeepEquals is more commonly used when no compare options are -required. - -Example calls: - - c.Assert(list, qt.CmpEquals(cmpopts.SortSlices), []int{42, 47}) - c.Assert(got, qt.CmpEquals(), []int{42, 47}) // Same as qt.DeepEquals. - -# CodecEquals - -CodecEquals returns a checker that checks for codec value equivalence. - - func CodecEquals( - marshal func(interface{}) ([]byte, error), - unmarshal func([]byte, interface{}) error, - opts ...cmp.Option, - ) Checker - -It expects two arguments: a byte slice or a string containing some -codec-marshaled data, and a Go value. - -It uses unmarshal to unmarshal the data into an interface{} value. -It marshals the Go value using marshal, then unmarshals the result into -an interface{} value. - -It then checks that the two interface{} values are deep-equal to one another, -using CmpEquals(opts) to perform the check. - -See JSONEquals for an example of this in use. - -# Contains - -Contains checks that a map, slice, array or string contains a value. It's the -same as using Any(Equals), except that it has a special case for strings - if -the first argument is a string, the second argument must also be a string and -strings.Contains will be used. - -For example: - - c.Assert("hello world", qt.Contains, "world") - c.Assert([]int{3,5,7,99}, qt.Contains, 7) - -# ContentEquals - -ContentEquals is is like DeepEquals but any slices in the compared values will be sorted before being compared. - -For example: - - c.Assert([]string{"c", "a", "b"}, qt.ContentEquals, []string{"a", "b", "c"}) - -# DeepEquals - -DeepEquals checks that two arbitrary values are deeply equal. -The comparison is done using the github.com/google/go-cmp/cmp package. -When comparing structs, by default no exported fields are allowed. -If a more sophisticated comparison is required, use CmpEquals (see below). - -Example call: - - c.Assert(got, qt.DeepEquals, []int{42, 47}) - -# Equals - -Equals checks that two values are equal, as compared with Go's == operator. - -For instance: - - c.Assert(answer, qt.Equals, 42) - -Note that the following will fail: - - c.Assert((*sometype)(nil), qt.Equals, nil) - -Use the IsNil checker below for this kind of nil check. - -# ErrorAs - -ErrorAs checks that the error is or wraps a specific error type. If so, it -assigns it to the provided pointer. This is analogous to calling errors.As. - -For instance: - - // Checking for a specific error type - c.Assert(err, qt.ErrorAs, new(*os.PathError)) - - // Checking fields on a specific error type - var pathError *os.PathError - if c.Check(err, qt.ErrorAs, &pathError) { - c.Assert(pathError.Path, Equals, "some_path") - } - -# ErrorIs - -ErrorIs checks that the error is or wraps a specific error value. This is -analogous to calling errors.Is. - -For instance: - - c.Assert(err, qt.ErrorIs, os.ErrNotExist) - -# ErrorMatches - -ErrorMatches checks that the provided value is an error whose message matches -the provided regular expression. - -For instance: - - c.Assert(err, qt.ErrorMatches, `bad wolf .*`) - -# HasLen - -HasLen checks that the provided value has the given length. - -For instance: - - c.Assert([]int{42, 47}, qt.HasLen, 2) - c.Assert(myMap, qt.HasLen, 42) - -# Implements - -Implements checks that the provided value implements an interface. The -interface is specified with a pointer to an interface variable. - -For instance: - - var rc io.ReadCloser - c.Assert(myReader, qt.Implements, &rc) - -# IsFalse - -IsFalse checks that the provided value is false. -The value must have a boolean underlying type. - -For instance: - - c.Assert(false, qt.IsFalse) - c.Assert(IsValid(), qt.IsFalse) - -# IsNil - -IsNil checks that the provided value is nil. - -For instance: - - c.Assert(got, qt.IsNil) - -As a special case, if the value is nil but implements the -error interface, it is still considered to be non-nil. -This means that IsNil will fail on an error value that happens -to have an underlying nil value, because that's -invariably a mistake. See https://golang.org/doc/faq#nil_error. - -So it's just fine to check an error like this: - - c.Assert(err, qt.IsNil) - -# IsNotNil - -IsNotNil is a Checker checking that the provided value is not nil. -IsNotNil is the equivalent of qt.Not(qt.IsNil) - -For instance: - - c.Assert(got, qt.IsNotNil) - -# IsTrue - -IsTrue checks that the provided value is true. -The value must have a boolean underlying type. - -For instance: - - c.Assert(true, qt.IsTrue) - c.Assert(myBoolean(false), qt.IsTrue) - -# JSONEquals - -JSONEquals checks whether a byte slice or string is JSON-equivalent to a Go -value. See CodecEquals for more information. - -It uses DeepEquals to do the comparison. If a more sophisticated comparison is -required, use CodecEquals directly. - -For instance: - - c.Assert(`{"First": 47.11}`, qt.JSONEquals, &MyStruct{First: 47.11}) - -# Matches - -Matches checks that a string or result of calling the String method -(if the value implements fmt.Stringer) matches the provided regular expression. - -For instance: - - c.Assert("these are the voyages", qt.Matches, `these are .*`) - c.Assert(net.ParseIP("1.2.3.4"), qt.Matches, `1.*`) - -# Not - -Not returns a Checker negating the given Checker. - -For instance: - - c.Assert(got, qt.Not(qt.IsNil)) - c.Assert(answer, qt.Not(qt.Equals), 42) - -# PanicMatches - -PanicMatches checks that the provided function panics with a message matching -the provided regular expression. - -For instance: - - c.Assert(func() {panic("bad wolf ...")}, qt.PanicMatches, `bad wolf .*`) - -# Satisfies - -Satisfies checks that the provided value, when used as argument of the provided -predicate function, causes the function to return true. The function must be of -type func(T) bool, having got assignable to T. - -For instance: - - // Check that an error from os.Open satisfies os.IsNotExist. - c.Assert(err, qt.Satisfies, os.IsNotExist) - - // Check that a floating point number is a not-a-number. - c.Assert(f, qt.Satisfies, math.IsNaN) - -# Deferred Execution - -The testing.TB.Cleanup helper provides the ability to defer the execution of -functions that will be run when the test completes. This is often useful for -creating OS-level resources such as temporary directories (see c.Mkdir). - -When targeting Go versions that don't have Cleanup (< 1.14), the same can be -achieved using c.Defer. In this case, to trigger the deferred behavior, calling -c.Done is required. For instance, if you create a *C instance at the top level, -you’ll have to add a defer to trigger the cleanups at the end of the test: - - defer c.Done() - -However, if you use quicktest to create a subtest, Done will be called -automatically at the end of that subtest. For example: - - func TestFoo(t *testing.T) { - c := qt.New(t) - c.Run("subtest", func(c *qt.C) { - c.Setenv("HOME", c.Mkdir()) - // Here $HOME is set the path to a newly created directory. - // At the end of the test the directory will be removed - // and HOME set back to its original value. - }) - } - -The c.Patch, c.Setenv, c.Unsetenv and c.Mkdir helpers use t.Cleanup for -cleaning up resources when available, and fall back to Defer otherwise. -*/ -package quicktest diff --git a/pkg/quicktest/error.go b/pkg/quicktest/error.go deleted file mode 100644 index 7b44a3e3..00000000 --- a/pkg/quicktest/error.go +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "fmt" -) - -// BadCheckf returns an error used to report a problem with the checker -// invocation or testing execution itself (like wrong number or type of -// arguments) rather than a real Check or Assert failure. -// This helper can be used when implementing checkers. -func BadCheckf(format string, a ...interface{}) error { - e := badCheck(fmt.Sprintf(format, a...)) - return &e -} - -// IsBadCheck reports whether the given error has been created by BadCheckf. -// This helper can be used when implementing checkers. -func IsBadCheck(err error) bool { - _, ok := err.(*badCheck) - return ok -} - -type badCheck string - -// Error implements the error interface. -func (e *badCheck) Error() string { - return "bad check: " + string(*e) -} - -// ErrSilent is the error used when there is no need to include in the failure -// output the "error" and "check" keys and all the keys automatically -// added for args. This helper can be used when implementing checkers. -var ErrSilent = fmt.Errorf("silent failure") diff --git a/pkg/quicktest/error_test.go b/pkg/quicktest/error_test.go deleted file mode 100644 index 3fb629f6..00000000 --- a/pkg/quicktest/error_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "errors" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestBadCheckf(t *testing.T) { - err := qt.BadCheckf("bad %s", "wolf") - expectedMessage := "bad check: bad wolf" - if err.Error() != expectedMessage { - t.Fatalf("error:\ngot %q\nwant %q", err, expectedMessage) - } -} - -func TestIsBadCheck(t *testing.T) { - err := qt.BadCheckf("bad wolf") - assertBool(t, qt.IsBadCheck(err), true) - err = errors.New("bad wolf") - assertBool(t, qt.IsBadCheck(err), false) -} - -var errBadWolf = &errTest{ - msg: "bad wolf", - formatted: true, -} - -var errBadWolfMultiLine = &errTest{ - msg: "bad wolf\nfaulty logic", - formatted: true, -} - -// errTest is an error type used in tests. -type errTest struct { - msg string - formatted bool -} - -// Error implements error. -func (err *errTest) Error() string { - return err.msg -} - -// Format implements fmt.Formatter. -func (err *errTest) Format(f fmt.State, c rune) { - if !f.Flag('+') || c != 'v' { - fmt.Fprint(f, "unexpected verb for formatting the error") - } - fmt.Fprint(f, err.Error()) - if err.formatted { - fmt.Fprint(f, "\n file:line") - } -} diff --git a/pkg/quicktest/export_test.go b/pkg/quicktest/export_test.go deleted file mode 100644 index 06b17b75..00000000 --- a/pkg/quicktest/export_test.go +++ /dev/null @@ -1,8 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -var ( - Prefixf = prefixf - TestingVerbose = &testingVerbose -) diff --git a/pkg/quicktest/format.go b/pkg/quicktest/format.go deleted file mode 100644 index a7c88b06..00000000 --- a/pkg/quicktest/format.go +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "unicode/utf8" - - "github.com/kr/pretty" -) - -// Format formats the given value as a string. It is used to print values in -// test failures unless that's changed by calling C.SetFormat. -func Format(v interface{}) string { - switch v := v.(type) { - case error: - s, ok := checkStringCall(v, v.Error) - if !ok { - return "e" - } - if msg := fmt.Sprintf("%+v", v); msg != s { - // The error has formatted itself with additional information. - // Leave that as is. - return msg - } - return "e" + quoteString(s) - case fmt.Stringer: - s, ok := checkStringCall(v, v.String) - if !ok { - return "s" - } - return "s" + quoteString(s) - case string: - return quoteString(v) - case uintptr, uint, uint8, uint16, uint32, uint64: - // Use decimal base (rather than hexadecimal) for representing uint types. - return fmt.Sprintf("%T(%d)", v, v) - } - if bytes, ok := byteSlice(v); ok && bytes != nil && utf8.Valid(bytes) { - // It's a top level slice of bytes that's also valid UTF-8. - // Ideally, this would happen at deeper levels too, - // but this is sufficient for some significant cases - // (json.RawMessage for example). - return fmt.Sprintf("%T(%s)", v, quoteString(string(bytes))) - } - // The pretty.Sprint equivalent does not quote string values. - return fmt.Sprintf("%# v", pretty.Formatter(v)) -} - -func byteSlice(x interface{}) ([]byte, bool) { - v := reflect.ValueOf(x) - if !v.IsValid() { - return nil, false - } - t := v.Type() - if t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 { - return v.Bytes(), true - } - return nil, false -} - -func quoteString(s string) string { - // TODO think more about what to do about multi-line strings. - if strings.Contains(s, `"`) && !strings.Contains(s, "\n") && strconv.CanBackquote(s) { - return "`" + s + "`" - } - return strconv.Quote(s) -} - -// checkStringCall calls f and returns its result, and reports if the call -// succeeded without panicking due to a nil pointer. -// If f panics and v is a nil pointer, it returns false. -func checkStringCall(v interface{}, f func() string) (s string, ok bool) { - defer func() { - err := recover() - if err == nil { - return - } - if val := reflect.ValueOf(v); val.Kind() == reflect.Ptr && val.IsNil() { - ok = false - return - } - panic(err) - }() - return f(), true -} - -type formatFunc func(interface{}) string diff --git a/pkg/quicktest/format_test.go b/pkg/quicktest/format_test.go deleted file mode 100644 index bc8d244f..00000000 --- a/pkg/quicktest/format_test.go +++ /dev/null @@ -1,146 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "bytes" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -var formatTests = []struct { - about string - value interface{} - want string -}{{ - about: "error value", - value: errBadWolf, - want: "bad wolf\n file:line", -}, { - about: "error value: not formatted", - value: &errTest{ - msg: "exterminate!", - }, - want: `e"exterminate!"`, -}, { - about: "error value: with quotes", - value: &errTest{ - msg: `cannot open "/no/such/file"`, - }, - want: "e`cannot open \"/no/such/file\"`", -}, { - about: "error value: multi-line", - value: &errTest{ - msg: `err: -"these are the voyages"`, - }, - want: `e"err:\n\"these are the voyages\""`, -}, { - about: "error value: with backquotes", - value: &errTest{ - msg: "cannot `open` \"file\"", - }, - want: `e"cannot ` + "`open`" + ` \"file\""`, -}, { - about: "error value: not guarding against nil", - value: (*errTest)(nil), - want: `e`, -}, { - about: "stringer", - value: bytes.NewBufferString("I am a stringer"), - want: `s"I am a stringer"`, -}, { - about: "stringer: with quotes", - value: bytes.NewBufferString(`I say "hello"`), - want: "s`I say \"hello\"`", -}, { - about: "stringer: not guarding against nil", - value: (*nilStringer)(nil), - want: "s", -}, { - about: "string", - value: "these are the voyages", - want: `"these are the voyages"`, -}, { - about: "string: with quotes", - value: `here is a quote: "`, - want: "`here is a quote: \"`", -}, { - about: "string: multi-line", - value: `foo -"bar" -`, - want: `"foo\n\"bar\"\n"`, -}, { - about: "string: with backquotes", - value: `"` + "`", - want: `"\"` + "`\"", -}, { - about: "slice", - value: []int{1, 2, 3}, - want: "[]int{1, 2, 3}", -}, { - about: "bytes", - value: []byte("hello"), - want: `[]uint8("hello")`, -}, { - about: "custom bytes type", - value: myBytes("hello"), - want: `quicktest_test.myBytes("hello")`, -}, { - about: "bytes with backquote", - value: []byte(`a "b" c`), - want: "[]uint8(`a \"b\" c`)", -}, { - about: "bytes with invalid utf-8", - value: []byte("\xff"), - want: "[]uint8{0xff}", -}, { - about: "nil byte slice", - value: []byte(nil), - want: "[]uint8(nil)", -}, { - about: "time", - value: goTime, - want: `s"2012-03-28 00:00:00 +0000 UTC"`, -}, { - about: "struct with byte slice", - value: struct{ X []byte }{[]byte("x")}, - want: "struct { X []uint8 }{\n X: {0x78},\n}", -}, { - about: "uint64", - value: uint64(17), - want: "uint64(17)", -}, { - about: "uint32", - value: uint32(17898), - want: "uint32(17898)", -}, { - about: "uintptr", - value: uintptr(13), - want: "uintptr(13)", -}, -} - -func TestFormat(t *testing.T) { - for _, test := range formatTests { - t.Run(test.about, func(t *testing.T) { - got := qt.Format(test.value) - if got != test.want { - t.Fatalf("format:\ngot %q\nwant %q", got, test.want) - } - }) - } -} - -type myBytes []byte - -// nilStringer is a stringer not guarding against nil. -type nilStringer struct { - msg string -} - -func (s *nilStringer) String() string { - return s.msg -} diff --git a/pkg/quicktest/iter.go b/pkg/quicktest/iter.go deleted file mode 100644 index 28abd8a7..00000000 --- a/pkg/quicktest/iter.go +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "fmt" - "reflect" -) - -// containerIter provides an interface for iterating over a container -// (map, slice or array). -type containerIter interface { - // next advances to the next item in the container. - next() bool - // key returns the current key as a string. - key() string - // value returns the current value. - value() reflect.Value -} - -// newIter returns an iterator over x which must be a map, slice -// or array. -func newIter(x interface{}) (containerIter, error) { - v := reflect.ValueOf(x) - switch v.Kind() { - case reflect.Map: - return newMapIter(v), nil - case reflect.Slice, reflect.Array: - return &sliceIter{ - index: -1, - v: v, - }, nil - default: - return nil, fmt.Errorf("map, slice or array required") - } -} - -// sliceIter implements containerIter for slices and arrays. -type sliceIter struct { - v reflect.Value - index int -} - -func (i *sliceIter) next() bool { - i.index++ - return i.index < i.v.Len() -} - -func (i *sliceIter) value() reflect.Value { - return i.v.Index(i.index) -} - -func (i *sliceIter) key() string { - return fmt.Sprintf("index %d", i.index) -} diff --git a/pkg/quicktest/mapiter.go b/pkg/quicktest/mapiter.go deleted file mode 100644 index b0e2b6f2..00000000 --- a/pkg/quicktest/mapiter.go +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "fmt" - "reflect" -) - -func newMapIter(v reflect.Value) containerIter { - return mapIter{v.MapRange()} -} - -// mapIter implements containerIter for maps. -type mapIter struct { - iter *reflect.MapIter -} - -func (i mapIter) next() bool { - return i.iter.Next() -} - -func (i mapIter) key() string { - return fmt.Sprintf("key %#v", i.iter.Key()) -} - -func (i mapIter) value() reflect.Value { - return i.iter.Value() -} diff --git a/pkg/quicktest/patch.go b/pkg/quicktest/patch.go deleted file mode 100644 index 282894b1..00000000 --- a/pkg/quicktest/patch.go +++ /dev/null @@ -1,72 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "io/ioutil" - "os" - "reflect" -) - -// Patch sets a variable to a temporary value for the duration of the test. -// -// It sets the value pointed to by the given destination to the given -// value, which must be assignable to the element type of the destination. -// -// At the end of the test (see "Deferred execution" in the package docs), the -// destination is set back to its original value. -func (c *C) Patch(dest, value interface{}) { - destv := reflect.ValueOf(dest).Elem() - oldv := reflect.New(destv.Type()).Elem() - oldv.Set(destv) - valuev := reflect.ValueOf(value) - if !valuev.IsValid() { - // This isn't quite right when the destination type is not - // nilable, but it's better than the complex alternative. - valuev = reflect.Zero(destv.Type()) - } - destv.Set(valuev) - c.cleanup(func() { - destv.Set(oldv) - }) -} - -// Unsetenv unsets an environment variable for the duration of a test. -func (c *C) Unsetenv(name string) { - c.Setenv(name, "") - os.Unsetenv(name) -} - -// Mkdir makes a temporary directory and returns its name. -// -// At the end of the test (see "Deferred execution" in the package docs), the -// directory and its contents are removed. -// -// Deprecated: in Go >= 1.15 use testing.TB.TempDir instead. -func (c *C) Mkdir() string { - td, ok := c.TB.(interface { - TempDir() string - }) - if ok { - return td.TempDir() - } - name, err := ioutil.TempDir("", "quicktest-") - c.Assert(err, Equals, nil) - c.cleanup(func() { - if err := os.RemoveAll(name); err != nil { - // Don't call c.Check because the stack traverse logic won't - // print the source location, so just log instead. - c.Errorf("quicktest cannot remove temporary testing directory: %v", err) - } - }) - return name -} - -// cleanup uses Cleanup when it can, falling back to using Defer. -func (c *C) cleanup(f func()) { - if tb, ok := c.TB.(cleaner); ok { - tb.Cleanup(f) - } else { - c.Defer(f) - } -} diff --git a/pkg/quicktest/patch_go1.14.go b/pkg/quicktest/patch_go1.14.go deleted file mode 100644 index 885c7d40..00000000 --- a/pkg/quicktest/patch_go1.14.go +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build go1.14 -// +build go1.14 - -package quicktest - -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - -// Patch sets a variable to a temporary value for the duration of the test. -// -// It sets the value pointed to by the given destination to the given value, -// which must be assignable to the element type of the destination. -// -// At the end of the test the destination is set back to its original value -// using t.Cleanup. -// -// The top level Patch function is only available on Go >= 1.14. Use (*C).Patch -// when on prior versions. -func Patch(t testing.TB, dest, value interface{}) { - New(t).Patch(dest, value) -} - -// Setenv sets an environment variable to a temporary value for the duration of -// the test. -// -// At the end of the test the environment variable is returned to its original -// value using t.Cleanup. -// -// The top level Setenv function is only available on Go >= 1.14. Use -// (*C).Setenv when on prior versions. -func Setenv(t testing.TB, name, val string) { - New(t).Setenv(name, val) -} - -// Unsetenv unsets an environment variable for the duration of a test. -// -// The top level Unsetenv function is only available on Go >= 1.14. Use -// (*C).Unsetenv when on prior versions. -func Unsetenv(t testing.TB, name string) { - New(t).Unsetenv(name) -} diff --git a/pkg/quicktest/patch_go1.14_test.go b/pkg/quicktest/patch_go1.14_test.go deleted file mode 100644 index 49d9dc1b..00000000 --- a/pkg/quicktest/patch_go1.14_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build go1.14 -// +build go1.14 - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "os" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestPatchSetInt(t *testing.T) { - i := 99 - t.Run("subtest", func(t *testing.T) { - qt.Patch(t, &i, 77) - qt.Assert(t, i, qt.Equals, 77) - }) - qt.Assert(t, i, qt.Equals, 99) -} - -func TestSetenv(t *testing.T) { - const envName = "SOME_VAR" - os.Setenv(envName, "initial") - t.Run("subtest", func(t *testing.T) { - qt.Setenv(t, envName, "a new value") - qt.Check(t, os.Getenv(envName), qt.Equals, "a new value") - }) - qt.Check(t, os.Getenv(envName), qt.Equals, "initial") -} - -func TestUnsetenv(t *testing.T) { - const envName = "SOME_VAR" - os.Setenv(envName, "initial") - t.Run("subtest", func(t *testing.T) { - qt.Unsetenv(t, envName) - _, ok := os.LookupEnv(envName) - qt.Assert(t, ok, qt.IsFalse) - }) - qt.Check(t, os.Getenv(envName), qt.Equals, "initial") -} diff --git a/pkg/quicktest/patch_go1.17.go b/pkg/quicktest/patch_go1.17.go deleted file mode 100644 index b43469e2..00000000 --- a/pkg/quicktest/patch_go1.17.go +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build !go1.17 -// +build !go1.17 - -package quicktest - -import "os" - -// Setenv sets an environment variable to a temporary value for the -// duration of the test. -// -// At the end of the test (see "Deferred execution" in the package docs), the -// environment variable is returned to its original value. -// -// This is the equivalent of testing.T.Setenv introduced in Go 1.17. -func (c *C) Setenv(name, val string) { - oldVal, oldOK := os.LookupEnv(name) - os.Setenv(name, val) - c.cleanup(func() { - if oldOK { - os.Setenv(name, oldVal) - } else { - os.Unsetenv(name) - } - }) -} diff --git a/pkg/quicktest/patch_go1.17_test.go b/pkg/quicktest/patch_go1.17_test.go deleted file mode 100644 index 41a40e11..00000000 --- a/pkg/quicktest/patch_go1.17_test.go +++ /dev/null @@ -1,36 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -//go:build !go1.17 -// +build !go1.17 - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "os" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -const envName = "SOME_VAR" - -func TestCSetenv(t *testing.T) { - c := qt.New(t) - os.Setenv(envName, "initial") - testCleanup(t, func(c *qt.C) { - c.Setenv(envName, "new value") - c.Check(os.Getenv(envName), qt.Equals, "new value") - }) - c.Check(os.Getenv(envName), qt.Equals, "initial") -} - -func TestCSetenvWithUnsetVariable(t *testing.T) { - c := qt.New(t) - os.Unsetenv(envName) - testCleanup(t, func(c *qt.C) { - c.Setenv(envName, "new value") - c.Check(os.Getenv(envName), qt.Equals, "new value") - }) - _, ok := os.LookupEnv(envName) - c.Assert(ok, qt.IsFalse) -} diff --git a/pkg/quicktest/patch_test.go b/pkg/quicktest/patch_test.go deleted file mode 100644 index 6676e947..00000000 --- a/pkg/quicktest/patch_test.go +++ /dev/null @@ -1,122 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "errors" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "os" - "path/filepath" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestCPatchSetInt(t *testing.T) { - c := qt.New(t) - i := 99 - testCleanup(t, func(c *qt.C) { - c.Patch(&i, 88) - c.Assert(i, qt.Equals, 88) - }) - c.Assert(i, qt.Equals, 99) -} - -func TestCPatchSetError(t *testing.T) { - c := qt.New(t) - oldErr := errors.New("foo") - newErr := errors.New("bar") - err := oldErr - testCleanup(t, func(c *qt.C) { - c.Patch(&err, newErr) - c.Assert(err, qt.Equals, newErr) - }) - c.Assert(err, qt.Equals, oldErr) -} - -func TestCPatchSetErrorToNil(t *testing.T) { - c := qt.New(t) - oldErr := errors.New("foo") - err := oldErr - testCleanup(t, func(c *qt.C) { - c.Patch(&err, nil) - c.Assert(err, qt.IsNil) - }) - c.Assert(err, qt.Equals, oldErr) -} - -func TestCPatchSetMapToNil(t *testing.T) { - c := qt.New(t) - oldMap := map[string]int{"foo": 1234} - m := oldMap - testCleanup(t, func(c *qt.C) { - c.Patch(&m, nil) - c.Assert(m, qt.IsNil) - }) - c.Assert(m, qt.DeepEquals, oldMap) -} - -func TestCPatchPanicsWhenNotAssignable(t *testing.T) { - c := qt.New(t) - i := 99 - type otherInt int - c.Assert(func() { - c.Patch(&i, otherInt(88)) - }, qt.PanicMatches, `reflect\.Set: value of type quicktest_test\.otherInt is not assignable to type int`) -} - -func TestCUnsetenv(t *testing.T) { - c := qt.New(t) - const envName = "SOME_VAR" - os.Setenv(envName, "initial") - testCleanup(t, func(c *qt.C) { - c.Unsetenv(envName) - _, ok := os.LookupEnv(envName) - c.Assert(ok, qt.IsFalse) - }) - c.Check(os.Getenv(envName), qt.Equals, "initial") -} - -func TestCUnsetenvWithUnsetVariable(t *testing.T) { - c := qt.New(t) - const envName = "SOME_VAR" - os.Unsetenv(envName) - testCleanup(t, func(c *qt.C) { - c.Unsetenv(envName) - _, ok := os.LookupEnv(envName) - c.Assert(ok, qt.IsFalse) - }) - _, ok := os.LookupEnv(envName) - c.Assert(ok, qt.IsFalse) -} - -func TestCMkdir(t *testing.T) { - c := qt.New(t) - var dir string - testCleanup(t, func(c *qt.C) { - dir = c.Mkdir() - c.Assert(dir, qt.Not(qt.Equals), "") - info, err := os.Stat(dir) - c.Assert(err, qt.IsNil) - c.Assert(info.IsDir(), qt.IsTrue) - f, err := os.Create(filepath.Join(dir, "hello")) - c.Assert(err, qt.IsNil) - f.Close() - }) - _, err := os.Stat(dir) - c.Assert(err, qt.Not(qt.IsNil)) -} - -func testCleanup(t *testing.T, f func(c *qt.C)) { - t.Run("subtest", func(t *testing.T) { - c := qt.New(t) - if _, ok := c.TB.(cleaner); !ok { - // Calling Done is required when testing on Go < 1.14. - defer c.Done() - } - f(c) - }) -} - -type cleaner interface { - Cleanup(func()) -} diff --git a/pkg/quicktest/qtsuite/suite.go b/pkg/quicktest/qtsuite/suite.go deleted file mode 100644 index 07c6059d..00000000 --- a/pkg/quicktest/qtsuite/suite.go +++ /dev/null @@ -1,122 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -/* -Package qtsuite allows quicktest to run test suites. - -A test suite is a value with one or more test methods. -For example, the following code defines a suite of test functions that starts -an HTTP server before running each test, and tears it down afterwards: - - type suite struct { - url string - } - - func (s *suite) Init(c *qt.C) { - hnd := func(w http.ResponseWriter, req *http.Request) { - fmt.Fprintf(w, "%s %s", req.Method, req.URL.Path) - } - srv := httptest.NewServer(http.HandlerFunc(hnd)) - c.Cleanup(srv.Close) - s.url = srv.URL - } - - func (s *suite) TestGet(c *qt.C) { - c.Parallel() - resp, err := http.Get(s.url) - c.Assert(err, qt.Equals, nil) - defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) - c.Assert(err, qt.Equals, nil) - c.Assert(string(b), qt.Equals, "GET /") - } - - func (s *suite) TestHead(c *qt.C) { - c.Parallel() - resp, err := http.Head(s.url + "/path") - c.Assert(err, qt.Equals, nil) - defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) - c.Assert(err, qt.Equals, nil) - c.Assert(string(b), qt.Equals, "") - c.Assert(resp.ContentLength, qt.Equals, int64(10)) - } - -The above code could be invoked from a test function like this: - - func TestHTTPMethods(t *testing.T) { - qtsuite.Run(qt.New(t), &suite{"http://example.com"}) - } -*/ -package qtsuite - -import ( - "reflect" - "strings" - "unicode" - "unicode/utf8" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -// Run runs each test method defined on the given value as a separate -// subtest. A test is a method of the form -// -// func (T) TestXxx(*quicktest.C) -// -// where Xxx does not start with a lowercase letter. -// -// If suite is a pointer, the value pointed to is copied before any -// methods are invoked on it; a new copy is made for each test. This -// means that it is OK for tests to modify fields in suite concurrently -// if desired - it's OK to call c.Parallel(). -// -// If suite has a method of the form -// -// func (T) Init(*quicktest.C) -// -// this method will be invoked before each test run. -func Run(c *qt.C, suite interface{}) { - sv := reflect.ValueOf(suite) - st := sv.Type() - init, hasInit := st.MethodByName("Init") - if hasInit && !isValidMethod(init) { - c.Fatal("wrong signature for Init, must be Init(*quicktest.C)") - } - for i := 0; i < st.NumMethod(); i++ { - m := st.Method(i) - if !isTestMethod(m) { - continue - } - c.Run(m.Name, func(c *qt.C) { - if !isValidMethod(m) { - c.Fatalf("wrong signature for %s, must be %s(*quicktest.C)", m.Name, m.Name) - } - - sv := sv - if st.Kind() == reflect.Ptr { - sv1 := reflect.New(st.Elem()) - sv1.Elem().Set(sv.Elem()) - sv = sv1 - } - args := []reflect.Value{sv, reflect.ValueOf(c)} - if hasInit { - init.Func.Call(args) - } - m.Func.Call(args) - }) - } -} - -var cType = reflect.TypeOf(&qt.C{}) - -func isTestMethod(m reflect.Method) bool { - if !strings.HasPrefix(m.Name, "Test") { - return false - } - r, n := utf8.DecodeRuneInString(m.Name[4:]) - return n == 0 || !unicode.IsLower(r) -} - -func isValidMethod(m reflect.Method) bool { - return m.Type.NumIn() == 2 && m.Type.NumOut() == 0 && m.Type.In(1) == cType -} diff --git a/pkg/quicktest/qtsuite/suite_test.go b/pkg/quicktest/qtsuite/suite_test.go deleted file mode 100644 index e7e8105f..00000000 --- a/pkg/quicktest/qtsuite/suite_test.go +++ /dev/null @@ -1,148 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package qtsuite_test - -import ( - "bytes" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" - "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest/qtsuite" -) - -func TestRunSuite(t *testing.T) { - c := qt.New(t) - var calls []call - tt := &testingT{} - qtsuite.Run(qt.New(tt), testSuite{calls: &calls}) - c.Assert(calls, qt.DeepEquals, []call{ - {"Test1", 0}, - {"Test4", 0}, - }) -} - -func TestRunSuiteEmbedded(t *testing.T) { - c := qt.New(t) - var calls []call - tt := &testingT{} - suite := struct { - testSuite - }{testSuite: testSuite{calls: &calls}} - qtsuite.Run(qt.New(tt), suite) - c.Assert(calls, qt.DeepEquals, []call{ - {"Test1", 0}, - {"Test4", 0}, - }) -} - -func TestRunSuitePtr(t *testing.T) { - c := qt.New(t) - var calls []call - tt := &testingT{} - qtsuite.Run(qt.New(tt), &testSuite{calls: &calls}) - c.Assert(calls, qt.DeepEquals, []call{ - {"Init", 0}, - {"Test1", 1}, - {"Init", 0}, - {"Test4", 1}, - }) -} - -type testSuite struct { - init int - calls *[]call -} - -func (s testSuite) addCall(name string) { - *s.calls = append(*s.calls, call{Name: name, Init: s.init}) -} - -func (s *testSuite) Init(*qt.C) { - s.addCall("Init") - s.init++ -} - -func (s testSuite) Test1(*qt.C) { - s.addCall("Test1") -} - -func (s testSuite) Test2() { - s.addCall("Test2") -} - -func (s testSuite) Test3(*testing.T) { - s.addCall("Test3") -} - -func (s testSuite) Test4(*qt.C) { - s.addCall("Test4") -} - -func (s testSuite) Test5(*qt.C) bool { - s.addCall("Test5") - return false -} - -func (s testSuite) Testa(*qt.C) { - s.addCall("Testa") -} - -type call struct { - Name string - Init int -} - -func TestInvalidInit(t *testing.T) { - c := qt.New(t) - tt := &testingT{} - tc := qt.New(tt) - qtsuite.Run(tc, invalidTestSuite{}) - c.Assert(tt.fatalString(), qt.Equals, "wrong signature for Init, must be Init(*quicktest.C)") -} - -type invalidTestSuite struct{} - -func (invalidTestSuite) Init() {} - -// testingT can be passed to qt.New for testing purposes. -type testingT struct { - testing.TB - - errorBuf bytes.Buffer - fatalBuf bytes.Buffer - - subTestResult bool - subTestName string - subTestT *testing.T -} - -// Error overrides *testing.T.Error so that messages are collected. -func (t *testingT) Error(a ...interface{}) { - fmt.Fprint(&t.errorBuf, a...) -} - -// Fatal overrides *testing.T.Fatal so that messages are collected and the -// goroutine is not killed. -func (t *testingT) Fatal(a ...interface{}) { - fmt.Fprint(&t.fatalBuf, a...) -} - -// Run overrides *testing.T.Run. -func (t *testingT) Run(name string, f func(t *testing.T)) bool { - t.subTestName, t.subTestT = name, &testing.T{} - ch := make(chan struct{}) - // Run the subtest in its own goroutine so that if it calls runtime.GoExit, - // we can still return appropriately. - go func() { - defer close(ch) - f(t.subTestT) - }() - <-ch - return t.subTestResult -} - -// fatalString returns the fatal error message. -func (t *testingT) fatalString() string { - return t.fatalBuf.String() -} diff --git a/pkg/quicktest/quicktest.go b/pkg/quicktest/quicktest.go deleted file mode 100644 index 242a4f74..00000000 --- a/pkg/quicktest/quicktest.go +++ /dev/null @@ -1,370 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "reflect" - "strings" - "sync" -) - -// Check runs the given check using the provided t and continues execution in -// case of failure. For instance: -// -// qt.Check(t, answer, qt.Equals, 42) -// qt.Check(t, got, qt.IsNil, qt.Commentf("iteration %d", i)) -// -// Additional args (not consumed by the checker), when provided, are included as -// comments in the failure output when the check fails. -func Check(t testing.TB, got interface{}, checker Checker, args ...interface{}) bool { - t.Helper() - return New(t).Check(got, checker, args...) -} - -// Assert runs the given check using the provided t and stops execution in case -// of failure. For instance: -// -// qt.Assert(t, got, qt.DeepEquals, []int{42, 47}) -// qt.Assert(t, got, qt.ErrorMatches, "bad wolf .*", qt.Commentf("a comment")) -// -// Additional args (not consumed by the checker), when provided, are included as -// comments in the failure output when the check fails. -func Assert(t testing.TB, got interface{}, checker Checker, args ...interface{}) bool { - t.Helper() - return New(t).Assert(got, checker, args...) -} - -// New returns a new checker instance that uses t to fail the test when checks -// fail. It only ever calls the Fatal, Error and (when available) Run methods -// of t. For instance. -// -// func TestFoo(t *testing.T) { -// t.Run("A=42", func(t *testing.T) { -// c := qt.New(t) -// c.Assert(a, qt.Equals, 42) -// }) -// } -// -// The library already provides some base checkers, and more can be added by -// implementing the Checker interface. -// -// If there is a likelihood that Defer will be called, then -// a call to Done should be deferred after calling New. -// For example: -// -// func TestFoo(t *testing.T) { -// c := qt.New(t) -// defer c.Done() -// c.Setenv("HOME", "/non-existent") -// c.Assert(os.Getenv("HOME"), qt.Equals, "/non-existent") -// }) -// -// A value of C that's has a non-nil TB field but is otherwise zero is valid. -// So: -// -// c := &qt.C{TB: t} -// -// is valid a way to create a C value; it's exactly the same as: -// -// c := qt.New(t) -// -// Methods on C may be called concurrently, assuming the underlying -// `testing.TB` implementation also allows that. -func New(t testing.TB) *C { - return &C{ - TB: t, - } -} - -// C is a quicktest checker. It embeds a testing.TB value and provides -// additional checking functionality. If an Assert or Check operation fails, it -// uses the wrapped TB value to fail the test appropriately. -type C struct { - testing.TB - - mu sync.Mutex - doneNeeded bool - deferred func() - format formatFunc -} - -// cleaner is implemented by testing.TB on Go 1.14 and later. -type cleaner interface { - Cleanup(func()) -} - -// Defer registers a function to be called when c.Done is -// called. Deferred functions will be called in last added, first called -// order. If c.Done is not called by the end of the test, the test -// may panic. Note that if Cleanup is called, there is no -// need to call Done. -// -// Deprecated: in Go >= 1.14 use testing.TB.Cleanup instead. -func (c *C) Defer(f func()) { - c.mu.Lock() - defer c.mu.Unlock() - if cleaner, ok := c.TB.(cleaner); ok { - // Use TB.Cleanup when available, but add a check - // that Done has been called so that we don't run - // into unexpected Go version incompatibilities. - if !c.doneNeeded { - c.doneNeeded = true - cleaner.Cleanup(func() { - c.mu.Lock() - defer c.mu.Unlock() - if c.doneNeeded { - panic("Done not called after Defer") - } - }) - } - - cleaner.Cleanup(f) - - return - } - - oldDeferred := c.deferred - if oldDeferred != nil { - c.deferred = func() { - defer oldDeferred() - f() - } - } else { - c.deferred = f - } -} - -// Done calls all the functions registered by Defer in reverse -// registration order. After it's called, the functions are -// unregistered, so calling Done twice will only call them once. -// -// When a test function is called by Run, Done will be called -// automatically on the C value passed into it. -// -// Deprecated: in Go >= 1.14 this is no longer needed if using -// testing.TB.Cleanup. -func (c *C) Done() { - c.mu.Lock() - deferred := c.deferred - c.deferred = nil - c.doneNeeded = false - c.mu.Unlock() - - if deferred != nil { - deferred() - } -} - -// SetFormat sets the function used to print values in test failures. -// By default Format is used. -// Any subsequent subtests invoked with c.Run will also use this function by -// default. -func (c *C) SetFormat(format func(interface{}) string) { - c.mu.Lock() - c.format = format - c.mu.Unlock() -} - -// getFormat returns the format function -// safely acquired under lock. -func (c *C) getFormat() func(interface{}) string { - c.mu.Lock() - defer c.mu.Unlock() - return c.format -} - -// Check runs the given check and continues execution in case of failure. -// For instance: -// -// c.Check(answer, qt.Equals, 42) -// c.Check(got, qt.IsNil, qt.Commentf("iteration %d", i)) -// -// Additional args (not consumed by the checker), when provided, are included -// as comments in the failure output when the check fails. -func (c *C) Check(got interface{}, checker Checker, args ...interface{}) bool { - c.TB.Helper() - return check(c, checkParams{ - fail: c.TB.Error, - checker: checker, - got: got, - args: args, - }) -} - -// Assert runs the given check and stops execution in case of failure. -// For instance: -// -// c.Assert(got, qt.DeepEquals, []int{42, 47}) -// c.Assert(got, qt.ErrorMatches, "bad wolf .*", qt.Commentf("a comment")) -// -// Additional args (not consumed by the checker), when provided, are included -// as comments in the failure output when the check fails. -func (c *C) Assert(got interface{}, checker Checker, args ...interface{}) bool { - c.TB.Helper() - return check(c, checkParams{ - fail: c.TB.Fatal, - checker: checker, - got: got, - args: args, - }) -} - -var ( - stringType = reflect.TypeOf("") - boolType = reflect.TypeOf(true) - tbType = reflect.TypeOf(new(testing.TB)).Elem() -) - -// Run runs f as a subtest of t called name. It's a wrapper around -// the Run method of c.TB that provides the quicktest checker to f. When -// the function completes, c.Done will be called to run any -// functions registered with c.Defer. -// -// c.TB must implement a Run method of the following form: -// -// Run(string, func(T)) bool -// -// where T is any type that is assignable to testing.TB. -// Implementations include *testing.T, *testing.B and *C itself. -// -// The TB field in the subtest will hold the value passed -// by Run to its argument function. -// -// func TestFoo(t *testing.T) { -// c := qt.New(t) -// c.Run("A=42", func(c *qt.C) { -// // This assertion only stops the current subtest. -// c.Assert(a, qt.Equals, 42) -// }) -// } -// -// A panic is raised when Run is called and the embedded concrete type does not -// implement a Run method with a correct signature. -func (c *C) Run(name string, f func(c *C)) bool { - badType := func(m string) { - panic(fmt.Sprintf("cannot execute Run with underlying concrete type %T (%s)", c.TB, m)) - } - m := reflect.ValueOf(c.TB).MethodByName("Run") - if !m.IsValid() { - // c.TB doesn't implement a Run method. - badType("no Run method") - } - mt := m.Type() - if mt.NumIn() != 2 || - mt.In(0) != stringType || - mt.NumOut() != 1 || - mt.Out(0) != boolType { - // The Run method doesn't have the right argument counts and types. - badType("wrong argument count for Run method") - } - farg := mt.In(1) - if farg.Kind() != reflect.Func || - farg.NumIn() != 1 || - farg.NumOut() != 0 || - !farg.In(0).AssignableTo(tbType) { - // The first argument to the Run function arg isn't right. - badType("bad first argument type for Run method") - } - cFormat := c.getFormat() - fv := reflect.MakeFunc(farg, func(args []reflect.Value) []reflect.Value { - c2 := New(args[0].Interface().(testing.TB)) - defer c2.Done() - c2.SetFormat(cFormat) - f(c2) - return nil - }) - return m.Call([]reflect.Value{reflect.ValueOf(name), fv})[0].Interface().(bool) -} - -// Parallel signals that this test is to be run in parallel with (and only with) other parallel tests. -// It's a wrapper around *testing.T.Parallel. -// -// A panic is raised when Parallel is called and the embedded concrete type does not -// implement Parallel, for instance if TB's concrete type is a benchmark. -func (c *C) Parallel() { - p, ok := c.TB.(interface { - Parallel() - }) - if !ok { - panic(fmt.Sprintf("cannot execute Parallel with underlying concrete type %T", c.TB)) - } - p.Parallel() -} - -// check performs the actual check with the provided params. -// In case of failure p.fail is called. In the fail report values are formatted -// using p.format. -func check(c *C, p checkParams) bool { - c.TB.Helper() - rp := reportParams{ - got: p.got, - args: p.args, - format: c.getFormat(), - } - if rp.format == nil { - // No format set; use the default: Format. - rp.format = Format - } - - // Allow checkers to annotate messages. - note := func(key string, value interface{}) { - rp.notes = append(rp.notes, note{ - key: key, - value: value, - }) - } - - // Ensure that we have a checker. - if p.checker == nil { - p.fail(report(BadCheckf("nil checker provided"), rp)) - return false - } - - // Extract comments if provided. - for len(p.args) > 0 { - comment, ok := p.args[len(p.args)-1].(Comment) - if !ok { - break - } - rp.comments = append([]Comment{comment}, rp.comments...) - p.args = p.args[:len(p.args)-1] - } - rp.args = p.args - - // Validate that we have the correct number of arguments. - rp.argNames = p.checker.ArgNames() - wantNumArgs := len(rp.argNames) - 1 - if gotNumArgs := len(rp.args); gotNumArgs != wantNumArgs { - if gotNumArgs > 0 { - note("got args", rp.args) - } - if wantNumArgs > 0 { - note("want args", Unquoted(strings.Join(rp.argNames[1:], ", "))) - } - var prefix string - if gotNumArgs > wantNumArgs { - prefix = "too many arguments provided to checker" - } else { - prefix = "not enough arguments provided to checker" - } - p.fail(report(BadCheckf("%s: got %d, want %d", prefix, gotNumArgs, wantNumArgs), rp)) - return false - } - - // Execute the check and report the failure if necessary. - if err := p.checker.Check(p.got, p.args, note); err != nil { - p.fail(report(err, rp)) - return false - } - return true -} - -// checkParams holds parameters for executing a check. -type checkParams struct { - fail func(...interface{}) - checker Checker - got interface{} - args []interface{} -} diff --git a/pkg/quicktest/quicktest_test.go b/pkg/quicktest/quicktest_test.go deleted file mode 100644 index 7bce4704..00000000 --- a/pkg/quicktest/quicktest_test.go +++ /dev/null @@ -1,753 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - "bytes" - "errors" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "strings" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -var _ testing.TB = (*qt.C)(nil) - -var cTests = []struct { - about string - checker qt.Checker - got interface{} - args []interface{} - format func(interface{}) string - expectedFailure string -}{{ - about: "success", - checker: qt.Equals, - got: 42, - args: []interface{}{42}, -}, { - about: "failure", - checker: qt.Equals, - got: "42", - args: []interface{}{"47"}, - expectedFailure: ` -error: - values are not equal -got: - "42" -want: - "47" -`, -}, { - about: "failure with % signs", - checker: qt.Equals, - got: "42%x", - args: []interface{}{"47%y"}, - expectedFailure: ` -error: - values are not equal -got: - "42%x" -want: - "47%y" -`, -}, { - about: "failure with comment", - checker: qt.Equals, - got: true, - args: []interface{}{false, qt.Commentf("apparently %v != %v", true, false)}, - expectedFailure: ` -error: - values are not equal -comment: - apparently true != false -got: - bool(true) -want: - bool(false) -`, -}, { - about: "another failure with comment", - checker: qt.IsNil, - got: 42, - args: []interface{}{qt.Commentf("bad wolf: %d", 42)}, - expectedFailure: ` -error: - got non-nil value -comment: - bad wolf: 42 -got: - int(42) -`, -}, { - about: "failure with constant comment", - checker: qt.IsNil, - got: "something", - args: []interface{}{qt.Commentf("these are the voyages")}, - expectedFailure: ` -error: - got non-nil value -comment: - these are the voyages -got: - "something" -`, -}, { - about: "failure with empty comment", - checker: qt.IsNil, - got: 47, - args: []interface{}{qt.Commentf("")}, - expectedFailure: ` -error: - got non-nil value -got: - int(47) -`, -}, { - about: "failure with multiple comments", - checker: qt.IsNil, - got: 42, - args: []interface{}{ - qt.Commentf("bad wolf: %d", 42), - qt.Commentf("second comment"), - }, - expectedFailure: ` -error: - got non-nil value -comment: - bad wolf: 42 -comment: - second comment -got: - int(42) -`, -}, { - about: "nil checker", - expectedFailure: ` -error: - bad check: nil checker provided -`, -}, { - about: "not enough arguments", - checker: qt.Equals, - got: 42, - args: []interface{}{}, - expectedFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -want args: - want -`, -}, { - about: "not enough arguments with comment", - checker: qt.DeepEquals, - got: 42, - args: []interface{}{qt.Commentf("test %d", 0)}, - expectedFailure: ` -error: - bad check: not enough arguments provided to checker: got 0, want 1 -comment: - test 0 -want args: - want -`, -}, { - about: "too many arguments", - checker: qt.Matches, - got: 42, - args: []interface{}{42, 47}, - expectedFailure: ` -error: - bad check: too many arguments provided to checker: got 2, want 1 -got args: - []interface {}{ - int(42), - int(47), - } -want args: - regexp -`, -}, { - about: "really too many arguments", - checker: qt.DeepEquals, - got: 42, - args: []interface{}{42, 47, nil, "stop"}, - expectedFailure: ` -error: - bad check: too many arguments provided to checker: got 4, want 1 -got args: - []interface {}{ - int(42), - int(47), - nil, - "stop", - } -want args: - want -`, -}, { - about: "too many arguments with comment", - checker: qt.IsNil, - got: 42, - args: []interface{}{nil, qt.Commentf("these are the voyages")}, - expectedFailure: ` -error: - bad check: too many arguments provided to checker: got 1, want 0 -comment: - these are the voyages -got args: - []interface {}{ - nil, - } -`, -}, { - about: "many arguments and notes", - checker: &testingChecker{ - argNames: []string{"arg1", "arg2", "arg3"}, - addNotes: func(note func(key string, value interface{})) { - note("note1", "these") - note("note2", qt.Unquoted("are")) - note("note3", "the") - note("note4", "voyages") - note("note5", true) - }, - err: errors.New("bad wolf"), - }, - got: 42, - args: []interface{}{"val2", "val3"}, - expectedFailure: ` -error: - bad wolf -note1: - "these" -note2: - are -note3: - "the" -note4: - "voyages" -note5: - bool(true) -arg1: - int(42) -arg2: - "val2" -arg3: - "val3" -`, -}, { - about: "many arguments and notes with the same value", - checker: &testingChecker{ - argNames: []string{"arg1", "arg2", "arg3", "arg4"}, - addNotes: func(note func(key string, value interface{})) { - note("note1", "value1") - note("note2", []int{42}) - note("note3", "value1") - note("note4", nil) - }, - err: errors.New("bad wolf"), - }, - got: "value1", - args: []interface{}{"value1", []int{42}, nil}, - expectedFailure: ` -error: - bad wolf -note1: - "value1" -note2: - []int{42} -note3: - -note4: - nil -arg1: - -arg2: - -arg3: - -arg4: - -`, -}, { - about: "many arguments and notes with custom format function", - checker: &testingChecker{ - argNames: []string{"arg1", "arg2", "arg3"}, - addNotes: func(note func(key string, value interface{})) { - note("note1", "these") - note("note2", qt.Unquoted("are")) - note("note3", "the") - note("note4", "voyages") - note("note5", true) - }, - err: errors.New("bad wolf"), - }, - got: 42, - args: []interface{}{"val2", "val3"}, - format: func(v interface{}) string { - return fmt.Sprintf("bad wolf %v", v) - }, - expectedFailure: ` -error: - bad wolf -note1: - bad wolf these -note2: - are -note3: - bad wolf the -note4: - bad wolf voyages -note5: - bad wolf true -arg1: - bad wolf 42 -arg2: - bad wolf val2 -arg3: - bad wolf val3 -`, -}, { - about: "bad check with notes", - checker: &testingChecker{ - argNames: []string{"got", "want"}, - addNotes: func(note func(key string, value interface{})) { - note("note", 42) - }, - err: qt.BadCheckf("bad wolf"), - }, - got: 42, - args: []interface{}{"want"}, - expectedFailure: ` -error: - bad check: bad wolf -note: - int(42) -`, -}, { - about: "silent failure with notes", - checker: &testingChecker{ - argNames: []string{"got", "want"}, - addNotes: func(note func(key string, value interface{})) { - note("note1", "first note") - note("note2", qt.Unquoted("second note")) - }, - err: qt.ErrSilent, - }, - got: 42, - args: []interface{}{"want"}, - expectedFailure: ` -note1: - "first note" -note2: - second note -`, -}} - -func TestCAssertCheck(t *testing.T) { - for _, test := range cTests { - t.Run("Assert: "+test.about, func(t *testing.T) { - if test.format != nil { - t.Skip("changing format not supported when using qt.Assert directly") - } - tt := &testingT{} - ok := qt.Assert(tt, test.got, test.checker, test.args...) - checkResult(t, ok, tt.fatalString(), test.expectedFailure) - if tt.errorString() != "" { - t.Fatalf("no error messages expected, but got %q", tt.errorString()) - } - }) - t.Run("Check: "+test.about, func(t *testing.T) { - if test.format != nil { - t.Skip("changing format not supported when using qt.Check directly") - } - tt := &testingT{} - ok := qt.Check(tt, test.got, test.checker, test.args...) - checkResult(t, ok, tt.errorString(), test.expectedFailure) - if tt.fatalString() != "" { - t.Fatalf("no fatal messages expected, but got %q", tt.fatalString()) - } - }) - t.Run("c.Assert: "+test.about, func(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - if test.format != nil { - c.SetFormat(test.format) - } - ok := c.Assert(test.got, test.checker, test.args...) - checkResult(t, ok, tt.fatalString(), test.expectedFailure) - if tt.errorString() != "" { - t.Fatalf("no error messages expected, but got %q", tt.errorString()) - } - }) - t.Run("c.Check: "+test.about, func(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - if test.format != nil { - c.SetFormat(test.format) - } - ok := c.Check(test.got, test.checker, test.args...) - checkResult(t, ok, tt.errorString(), test.expectedFailure) - if tt.fatalString() != "" { - t.Fatalf("no fatal messages expected, but got %q", tt.fatalString()) - } - }) - } -} - -func TestCRunSuccess(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - var run bool - subTestName := "my test" - ok := c.Run(subTestName, func(innerC *qt.C) { - run = true - if innerC == c { - t.Fatal("subtest C: same instance provided") - } - if innerC.TB != tt.subTestT { - t.Fatalf("subtest testing object: got %p, want %p", innerC.TB, tt.subTestT) - } - if tt.subTestName != subTestName { - t.Fatalf("subtest name: got %q, want %q", tt.subTestName, subTestName) - } - }) - assertBool(t, run, true) - assertBool(t, ok, false) - - // Simulate a test success. - tt.subTestResult = true - ok = c.Run(subTestName, func(innerC *qt.C) {}) - assertBool(t, ok, true) -} - -func TestCRunOnBenchmark(t *testing.T) { - called := false - testing.Benchmark(func(b *testing.B) { - c := qt.New(b) - c.Run("c", func(c *qt.C) { - b1, ok := c.TB.(*testing.B) - if !ok { - t.Errorf("c.TB is type %T not *testing.B", c.TB) - return - } - if b1 == b { - t.Errorf("c.TB hasn't been given a new B value") - return - } - called = true - }) - }) - if !called { - t.Fatalf("sub-benchmark was never called") - } -} - -// wrongRun1 has Run method with wrong arg count. -type wrongRun1 struct { - testing.TB -} - -func (wrongRun1) Run() {} - -// wrongRun2 has no Run method. -type wrongRun2 struct { - testing.TB -} - -// wrongRun3 has Run method that takes a type not -// assignable to testing.TB. -type wrongRun3 struct { - testing.TB -} - -func (wrongRun3) Run(string, func(string)) bool { return false } - -// wrongRun4 has Run method that doesn't return bool. -type wrongRun4 struct { - testing.TB -} - -func (wrongRun4) Run(string, func(*testing.T)) {} - -var CRunPanicTests = []struct { - tb testing.TB - expectPanic string -}{{ - tb: wrongRun1{}, - expectPanic: "wrong argument count for Run method", -}, { - tb: wrongRun2{}, - expectPanic: "no Run method", -}, { - tb: wrongRun3{}, - expectPanic: "bad first argument type for Run method", -}, { - tb: wrongRun4{}, - expectPanic: "wrong argument count for Run method", -}} - -func TestCRunPanic(t *testing.T) { - for _, test := range CRunPanicTests { - t.Run(fmt.Sprintf("%T", test.tb), func(t *testing.T) { - c := qt.New(test.tb) - defer func() { - got := recover() - want := fmt.Sprintf( - "cannot execute Run with underlying concrete type %T (%s)", - test.tb, test.expectPanic, - ) - if got != want { - t.Fatalf("unexpected panic recover message; got %q want %q", got, want) - } - }() - c.Run("panic", func(innerC *qt.C) {}) - }) - } -} - -func TestCRunFormat(t *testing.T) { - tt, innerTT := &testingT{}, &testingT{} - c := qt.New(tt) - c.SetFormat(func(v interface{}) string { - return fmt.Sprintf("myfmt(%v)", v) - }) - c.Run("my test", func(innerC *qt.C) { - innerC.TB = innerTT - innerC.Check(42, qt.Equals, nil) - }) - assertPrefix(t, innerTT.errorString(), ` -error: - values are not equal -got: - myfmt(42) -want: - myfmt() -`) -} - -func TestHelper(t *testing.T) { - tt := &testingT{} - qt.Assert(tt, true, qt.IsFalse) - if tt.helperCalls != 3 { - t.Fatalf("want 3 calls (Assert, c.Assert, check), got %d", tt.helperCalls) - } -} - -func TestCHelper(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - c.Assert(true, qt.IsFalse) - if tt.helperCalls != 2 { - t.Fatalf("want 2 calls (c.Assert, check), got %d", tt.helperCalls) - } -} - -func TestCParallel(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - c.Parallel() - if !tt.parallel { - t.Fatalf("parallel not called") - } -} - -func TestCParallelPanic(t *testing.T) { - c := qt.New(&testing.B{}) - defer func() { - r := recover() - if r != "cannot execute Parallel with underlying concrete type *testing.B" { - t.Fatalf("unexpected panic recover: %v", r) - } - }() - c.Parallel() -} - -func TestCDefer(t *testing.T) { - c := qt.New(t) - var defers []int - c.Run("subtest", func(c *qt.C) { - c.Defer(func() { defers = append(defers, 1) }) - c.Defer(func() { defers = append(defers, 2) }) - // Calling Done twice should not do anything more. - c.Done() - }) - c.Assert(defers, qt.DeepEquals, []int{2, 1}) -} - -func TestCDeferCalledEvenAfterGoexit(t *testing.T) { - // The testing package uses runtime.Goexit on - // assertion failure, so check that defers are still - // called in that case. - c := qt.New(t) - defers := 0 - c.Run("subtest", func(c *qt.C) { - c.Defer(func() { - defers++ - }) - c.Defer(func() { - c.SkipNow() - }) - }) - c.Assert(defers, qt.Equals, 1) -} - -func TestCRunDefer(t *testing.T) { - c := qt.New(t) - defers := 0 - c.Run("subtest", func(c *qt.C) { - c.Run("x", func(c *qt.C) { - c.Defer(func() { defers++ }) - }) - }) - c.Assert(defers, qt.Equals, 1) -} - -type customT struct { - *testing.T - data int -} - -func (t *customT) Run(name string, f func(*customT)) bool { - return t.T.Run(name, func(t1 *testing.T) { - f(&customT{t1, t.data}) - }) -} - -func TestCRunCustomType(t *testing.T) { - ct := &customT{t, 99} - c := qt.New(ct) - called := 0 - c.Run("test", func(c *qt.C) { - called++ - ct1, ok := c.TB.(*customT) - if !ok { - t.Error("TB isn't expected type") - } - if ct1.data != ct.data { - t.Errorf("data not copied correctly; got %v want %v", ct1.data, ct.data) - } - if ct1 == ct { - t.Errorf("old instance passed, not new") - } - }) - if called != 1 { - t.Fatalf("subtest was called %d times, not once", called) - } -} - -func checkResult(t *testing.T, ok bool, got, want string) { - t.Helper() - if want != "" { - assertPrefix(t, got, want+"stack:\n") - assertBool(t, ok, false) - return - } - if got != "" { - t.Fatalf("output:\ngot %q\nwant empty", got) - } - assertBool(t, ok, true) -} - -// testingT can be passed to qt.New for testing purposes. -type testingT struct { - testing.TB - - errorBuf bytes.Buffer - fatalBuf bytes.Buffer - - subTestResult bool - subTestName string - subTestT *testing.T - - helperCalls int - parallel bool -} - -// Error overrides testing.TB.Error so that messages are collected. -func (t *testingT) Error(a ...interface{}) { - fmt.Fprint(&t.errorBuf, a...) -} - -// Fatal overrides testing.TB.Fatal so that messages are collected and the -// goroutine is not killed. -func (t *testingT) Fatal(a ...interface{}) { - fmt.Fprint(&t.fatalBuf, a...) -} - -// Parallel overrides testing.TB.Parallel in order to record the call. -func (t *testingT) Parallel() { - t.parallel = true -} - -// Helper overrides testing.TB.Helper in order to count calls. -func (t *testingT) Helper() { - t.helperCalls += 1 -} - -// Fatal overrides *testing.T.Fatal so that messages are collected and the -// goroutine is not killed. -func (t *testingT) Run(name string, f func(t *testing.T)) bool { - t.subTestName, t.subTestT = name, &testing.T{} - f(t.subTestT) - return t.subTestResult -} - -// errorString returns the error message. -func (t *testingT) errorString() string { - return t.errorBuf.String() -} - -// fatalString returns the fatal error message. -func (t *testingT) fatalString() string { - return t.fatalBuf.String() -} - -// assertPrefix fails if the got value does not have the given prefix. -func assertPrefix(t testing.TB, got, prefix string) { - t.Helper() - if prefix == "" { - t.Fatal("prefix: empty value provided") - } - if !strings.HasPrefix(got, prefix) { - t.Fatalf(`prefix: -got %q -want %q --------------------- got -------------------- -%s --------------------- want ------------------- -%s ----------------------------------------------`, got, prefix, got, prefix) - } -} - -// assertBool fails if the given boolean values don't match. -func assertBool(t testing.TB, got, want bool) { - t.Helper() - if got != want { - t.Fatalf("bool:\ngot %v\nwant %v", got, want) - } -} - -// testingChecker is a quicktest.Checker used in tests. It receives the -// provided argNames, adds notes via the provided addNotes function, and when -// the check is run the provided error is returned. -type testingChecker struct { - argNames []string - addNotes func(note func(key string, value interface{})) - err error -} - -// Check implements quicktest.Checker by returning the stored error. -func (c *testingChecker) Check(got interface{}, args []interface{}, note func(key string, value interface{})) error { - if c.addNotes != nil { - c.addNotes(note) - } - return c.err -} - -// Info implements quicktest.Checker by returning the stored args. -func (c *testingChecker) ArgNames() []string { - return c.argNames -} diff --git a/pkg/quicktest/race_test.go b/pkg/quicktest/race_test.go deleted file mode 100644 index 7a202b90..00000000 --- a/pkg/quicktest/race_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "sync" - "sync/atomic" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -func TestConcurrentMethods(t *testing.T) { - // This test is designed to be run with the race - // detector enabled. It checks that C methods - // are safe to call concurrently. - - // N holds the number of iterations to run any given - // operation concurrently with the others. - const N = 100 - - var x, y int32 - c := qt.New(dummyT{t}) - c.Run("subtest", func(c *qt.C) { - var wg sync.WaitGroup - // start calls f in two goroutines, each - // running it N times. - // All the goroutines get started before we actually - // start them running, so that the race detector - // has a better chance of catching issues. - gogogo := make(chan struct{}) - start := func(f func()) { - repeat := func() { - defer wg.Done() - <-gogogo - for i := 0; i < N; i++ { - f() - } - } - wg.Add(2) - go repeat() - go repeat() - } - start(func() { - c.Defer(func() { - atomic.AddInt32(&x, 1) - }) - c.Defer(func() { - atomic.AddInt32(&y, 1) - }) - }) - start(func() { - c.Done() - }) - start(func() { - c.SetFormat(func(v interface{}) string { - return "x" - }) - }) - start(func() { - // Do an assert to exercise the formatter. - c.Check(true, qt.Equals, false) - }) - start(func() { - c.Run("", func(c *qt.C) {}) - }) - close(gogogo) - wg.Wait() - }) - // Check that all the defer functions ran OK. - if x != N*2 || y != N*2 { - t.Fatalf("unexpected x, y counts; got %d, %d; want %d, %d", x, y, N*2, N*2) - } -} - -// dummyT wraps a *testing.T value suitable -// for TestConcurrentMethods so that calling Error -// won't fail the test and that it implements -// Run correctly. -type dummyT struct { - *testing.T -} - -func (dummyT) Error(...interface{}) {} - -func (t dummyT) Run(name string, f func(t dummyT)) bool { - return t.T.Run(name, func(t *testing.T) { - f(dummyT{t}) - }) -} diff --git a/pkg/quicktest/report.go b/pkg/quicktest/report.go deleted file mode 100644 index 83d01591..00000000 --- a/pkg/quicktest/report.go +++ /dev/null @@ -1,248 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest - -import ( - "bytes" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "go/ast" - "go/parser" - "go/printer" - "go/token" - "io" - "reflect" - "runtime" - "strings" -) - -// reportParams holds parameters for reporting a test error. -type reportParams struct { - // argNames holds the names for the arguments passed to the checker. - argNames []string - // got holds the value that was checked. - got interface{} - // args holds all other arguments (if any) provided to the checker. - args []interface{} - // comment optionally holds the comment passed when performing the check. - comments []Comment - // notes holds notes added while doing the check. - notes []note - // format holds the format function that must be used when outputting - // values. - format formatFunc -} - -// Unquoted indicates that the string must not be pretty printed in the failure -// output. This is useful when a checker calls note and does not want the -// provided value to be quoted. -type Unquoted string - -// SuppressedIfLong indicates that the value must be suppressed if verbose -// testing is off and the pretty printed version of the value is long. This is -// useful when a checker calls note and does not want the provided value to be -// printed in non-verbose test runs if the value is too long. -type SuppressedIfLong struct { - // Value holds the original annotated value. - Value interface{} -} - -// longValueLines holds the number of lines after which a value is long. -const longValueLines = 10 - -// report generates a failure report for the given error, optionally including -// in the output the checker arguments, comment and notes included in the -// provided report parameters. -func report(err error, p reportParams) string { - var buf bytes.Buffer - buf.WriteByte('\n') - writeError(&buf, err, p) - writeStack(&buf) - return buf.String() -} - -// writeError writes a pretty formatted output of the given error using the -// provided report parameters. -func writeError(w io.Writer, err error, p reportParams) { - ptrs := make(map[string]interface{}) - values := make(map[string]string) - - printPair := func(key string, value interface{}) { - fmt.Fprintln(w, key+":") - var v string - - if u, ok := value.(Unquoted); ok { - // Output the raw string without quotes. - v = string(u) - } else if s, ok := value.(SuppressedIfLong); ok { - // Check whether the output is too long and must be suppressed. - v = p.format(s.Value) - if !testingVerbose() { - if n := strings.Count(v, "\n"); n > longValueLines { - fmt.Fprint(w, prefixf(prefix, "", n)) - return - } - } - } else { - // Check whether the output has been already seen. - v = p.format(value) - isPtr := reflect.ValueOf(value).Kind() == reflect.Ptr - if k := values[v]; k != "" { - if previousValue, ok := ptrs[k]; ok && isPtr && previousValue != value { - fmt.Fprint(w, prefixf(prefix, "", k)) - return - } - fmt.Fprint(w, prefixf(prefix, "", k)) - return - } - if isPtr { - ptrs[key] = value - } - } - - values[v] = key - fmt.Fprint(w, prefixf(prefix, "%s", v)) - } - - // Write the checker error. - if err != ErrSilent { - printPair("error", Unquoted(err.Error())) - } - - // Write comments if provided. - for _, c := range p.comments { - if comment := c.String(); comment != "" { - printPair("comment", Unquoted(comment)) - } - } - - // Write notes if present. - for _, n := range p.notes { - printPair(n.key, n.value) - } - if IsBadCheck(err) || err == ErrSilent { - // For errors in the checker invocation or for silent errors, do not - // show output from args. - return - } - - // Write provided args. - for i, arg := range append([]interface{}{p.got}, p.args...) { - printPair(p.argNames[i], arg) - } -} - -// testingVerbose is defined as a variable for testing. -var testingVerbose = func() bool { - return testing.Verbose() -} - -// writeStack writes the traceback information for the current failure into the -// provided writer. -func writeStack(w io.Writer) { - fmt.Fprintln(w, "stack:") - pc := make([]uintptr, 8) - sg := &stmtGetter{ - fset: token.NewFileSet(), - files: make(map[string]*ast.File, 8), - config: &printer.Config{ - Mode: printer.UseSpaces, - Tabwidth: 4, - }, - } - runtime.Callers(5, pc) - frames := runtime.CallersFrames(pc) - thisPackage := reflect.TypeOf(C{}).PkgPath() + "." - for { - frame, more := frames.Next() - if strings.HasPrefix(frame.Function, "testing.") { - // Stop before getting back to stdlib test runner calls. - break - } - if fname := strings.TrimPrefix(frame.Function, thisPackage); fname != frame.Function { - if ast.IsExported(fname) { - // Continue without printing frames for quicktest exported API. - continue - } - // Stop when entering quicktest internal calls. - // This is useful for instance when using qtsuite. - break - } - fmt.Fprint(w, prefixf(prefix, "%s:%d", frame.File, frame.Line)) - if strings.HasSuffix(frame.File, ".go") { - stmt, err := sg.Get(frame.File, frame.Line) - if err != nil { - fmt.Fprint(w, prefixf(prefix+prefix, "<%s>", err)) - } else { - fmt.Fprint(w, prefixf(prefix+prefix, "%s", stmt)) - } - } - if !more { - // There are no more callers. - break - } - } -} - -type stmtGetter struct { - fset *token.FileSet - files map[string]*ast.File - config *printer.Config -} - -// Get returns the lines of code of the statement at the given file and line. -func (sg *stmtGetter) Get(file string, line int) (string, error) { - f := sg.files[file] - if f == nil { - var err error - f, err = parser.ParseFile(sg.fset, file, nil, parser.ParseComments) - if err != nil { - return "", fmt.Errorf("cannot parse source file: %s", err) - } - sg.files[file] = f - } - var stmt string - ast.Inspect(f, func(n ast.Node) bool { - if n == nil || stmt != "" { - return false - } - pos := sg.fset.Position(n.Pos()).Line - end := sg.fset.Position(n.End()).Line - // Go < v1.9 reports the line where the statements ends, not the line - // where it begins. - if line == pos || line == end { - var buf bytes.Buffer - // TODO: include possible comment after the statement. - sg.config.Fprint(&buf, sg.fset, &printer.CommentedNode{ - Node: n, - Comments: f.Comments, - }) - stmt = buf.String() - return false - } - return pos < line && line <= end - }) - return stmt, nil -} - -// prefixf formats the given string with the given args. It also inserts the -// final newline if needed and indentation with the given prefix. -func prefixf(prefix, format string, args ...interface{}) string { - var buf []byte - s := strings.TrimSuffix(fmt.Sprintf(format, args...), "\n") - for _, line := range strings.Split(s, "\n") { - buf = append(buf, prefix...) - buf = append(buf, line...) - buf = append(buf, '\n') - } - return string(buf) -} - -// note holds a key/value annotation. -type note struct { - key string - value interface{} -} - -// prefix is the string used to indent blocks of output. -const prefix = " " diff --git a/pkg/quicktest/report_test.go b/pkg/quicktest/report_test.go deleted file mode 100644 index a4690859..00000000 --- a/pkg/quicktest/report_test.go +++ /dev/null @@ -1,185 +0,0 @@ -// Licensed under the MIT license, see LICENSE file for details. - -package quicktest_test - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "runtime" - "strings" - - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" -) - -// The tests in this file rely on their own source code lines. - -func TestReportOutput(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - c.Assert(42, qt.Equals, 47) - want := ` -error: - values are not equal -got: - int(42) -want: - int(47) -stack: - $file:18 - c.Assert(42, qt.Equals, 47) -` - assertReport(t, tt, want) -} - -func f1(c *qt.C) { - f2(c) -} - -func f2(c *qt.C) { - c.Assert(42, qt.IsNil) // Real assertion here! -} - -func TestIndirectReportOutput(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - f1(c) - want := ` -error: - got non-nil value -got: - int(42) -stack: - $file:38 - c.Assert(42, qt.IsNil) - $file:34 - f2(c) - $file:44 - f1(c) -` - assertReport(t, tt, want) -} - -func TestMultilineReportOutput(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - c.Assert( - "this string", // Comment 1. - qt.Equals, - "another string", - qt.Commentf("a comment"), // Comment 2. - ) // Comment 3. - want := ` -error: - values are not equal -comment: - a comment -got: - "this string" -want: - "another string" -stack: - $file:64 - c.Assert( - "this string", // Comment 1. - qt.Equals, - "another string", - qt.Commentf("a comment"), // Comment 2. - ) -` - assertReport(t, tt, want) -} - -func TestCmpReportOutput(t *testing.T) { - tt := &testingT{} - c := qt.New(tt) - gotExamples := []*reportExample{{ - AnInt: 42, - }, { - AnInt: 47, - }, { - AnInt: 1, - }, { - AnInt: 2, - }} - wantExamples := []*reportExample{{ - AnInt: 42, - }, { - AnInt: 47, - }, { - AnInt: 2, - }, { - AnInt: 1, - }, {}} - c.Assert(gotExamples, qt.DeepEquals, wantExamples) - want := ` -error: - values are not deep equal -diff (-got +want): - []*quicktest_test.reportExample{ - &{AnInt: 42}, - &{AnInt: 47}, - + &{AnInt: 2}, - &{AnInt: 1}, - - &{AnInt: 2}, - + &{}, - } -got: - []*quicktest_test.reportExample{ - &quicktest_test.reportExample{AnInt:42}, - &quicktest_test.reportExample{AnInt:47}, - &quicktest_test.reportExample{AnInt:1}, - &quicktest_test.reportExample{AnInt:2}, - } -want: - []*quicktest_test.reportExample{ - &quicktest_test.reportExample{AnInt:42}, - &quicktest_test.reportExample{AnInt:47}, - &quicktest_test.reportExample{AnInt:2}, - &quicktest_test.reportExample{AnInt:1}, - &quicktest_test.reportExample{}, - } -stack: - $file:112 - c.Assert(gotExamples, qt.DeepEquals, wantExamples) -` - assertReport(t, tt, want) -} - -func TestTopLevelAssertReportOutput(t *testing.T) { - tt := &testingT{} - qt.Assert(tt, 42, qt.Equals, 47) - want := ` -error: - values are not equal -got: - int(42) -want: - int(47) -stack: - $file:149 - qt.Assert(tt, 42, qt.Equals, 47) -` - assertReport(t, tt, want) -} - -func assertReport(t *testing.T, tt *testingT, want string) { - got := strings.Replace(tt.fatalString(), "\t", " ", -1) - // go-cmp can include non-breaking spaces in its output. - got = strings.Replace(got, "\u00a0", " ", -1) - // Adjust for file names in different systems. - _, file, _, ok := runtime.Caller(0) - assertBool(t, ok, true) - want = strings.Replace(want, "$file", file, -1) - if got != want { - t.Fatalf(`failure: -%q -%q ------------------------------- got ------------------------------ -%s------------------------------ want ----------------------------- -%s-----------------------------------------------------------------`, - got, want, got, want) - } -} - -type reportExample struct { - AnInt int -} diff --git a/pkg/slogassert/.gitignore b/pkg/slogassert/.gitignore deleted file mode 100644 index 49e2f257..00000000 --- a/pkg/slogassert/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*~ -.#~* diff --git a/pkg/slogassert/LICENSE b/pkg/slogassert/LICENSE deleted file mode 100644 index 9463e514..00000000 --- a/pkg/slogassert/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2023 Barracuda Networks, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/pkg/slogassert/README.md b/pkg/slogassert/README.md deleted file mode 100644 index 71b2c9c6..00000000 --- a/pkg/slogassert/README.md +++ /dev/null @@ -1,193 +0,0 @@ -# slogassert - - - import "github.com/thejerf/slogassert" - -[![GoDoc](https://pkg.go.dev/badge/github.com/thejerf/slogassert)](https://pkg.go.dev/github.com/thejerf/slogassert) - -## About Slogassert - -slogassert implements a _testing handler_ for slog. - -All important observable results of code should be tested. While -commonly ignored by people writing tests, log messages are often -important things to test for, for several reasons: - - * Because they are not tested for, it is suprisingly easy for them to - break without anyone realizing. - * Log messages can have security impact. Any log messages that may be - used to reconstruct a security incident should be tested to ensure - they contain the data they are supposed to contain. - * Even when you don't otherwise deeply care about log - messages, log messages can often still double as a way of asserting - that certain code was actually reached, and the value of variables - at the time it was reached is as expected. - -While I wouldn't pull in slogassert just for that third point, if the -first two are in play for your code base, slog's strong focus on -structured attributes means that log messages can also double as -testing probe points within your code that may be otherwise -unreachable. I don't use this a lot but when you need it it's very -useful. (You may find it helpful to create a testing log level even -above Debug for this.) - -This implements a handler for slog that more-or-less records the -incoming messages, then provides a mechanism for testing for the -presence and number of log messages at a variety of different detail -levels. As log messages are tested for and matched by assertions, they -are removed from the record. If an assertion is made and no log -messages match, a testing error will be thrown. - -Once all the assertions are complete, an assertion should be made that -all log messages are accounted for. If there are unaccounted log -messages, the test will fail at the end. - -Because this is a test logger, some things normally too expensive to -be done in normal logging are done, like taking a full stack trace at -the location of all log messages that are recorded. This assists in -diagnosing where any unasserted log messages are coming from. - -See [usage in the godoc](https://pkg.go.dev/github.com/thejerf/slogassert). - -This also includes a null logger, which I am surprised is not in the -library itself as I write this since a `nil` slog.Logger is invalid. - -## Release Status - -`slogassert` is **beta**. I consider the package as it nows stands to -be a 1.0 release candidate, but it is not yet officially 1.0. - -The code is covered as much as possible, however it is not possible to -directly test covering the code that calls fatal errors, so that code -can not be covered or directly tested. - -## Version Numbering - -This repository will use semantic versioning. - -I will be signing this repository with the ["jerf" keybase -account](https://keybase.io/jerf). If you are viewing this repository -through GitHub, you should see the commits as showing as "verified" in -the commit view. - -(Bear in mind that due to the nature of how git commit signing works, -there may be runs of unverified commits; what matters is that the top -one is signed.) - -## Version History - -* v0.3.4: - * Create a custom interface for just the components of testing.TB - * slogassert actually uses. -* v0.3.3: - * Export LogMessageMatch.Matches for external use. - * Add utility function for testing. - * Take the `testing.TB` interface rather than a constant `*testing.T`. -* v0.3.2: - * A LogValuer being used for an attribute match would fail to match - because slogassert wouldn't resolve the value, but try to match - the value against the slog.Value. If the LogValuer did something - like change types or something, it would never match. Now values - that implement LogValuer can be used directly in attribute - matches. See the `ValueAsString` in `assertions_test.go` if you - don't know what I mean. -* v0.3.1: - * Annotate the internal .Assert\* functions as `t.Helper()`s to - improve error messages when an assert fails. -* v0.3.0 more **BREAKING CHANGES**: - * Significant API rewrite. This: - * Exposes Assert directly, for functional-matching based - assertions, which enables a lot of more complicated scenarios. - * Now that the general power is available to end users, the - package doesn't need to offer every marginal match method, so - I'm removing the built-in message + level assertion. It's easy - now to implement yourself if it's useful, and I haven't used it - yet in my own code so I question its general utility, sandwiched - between the very useful "please assert this message" (useful - because it is agnostic about levels) and "please assert this - exact match" methods. - * If you wrap another slog Handler with this, we need to properly - pass WithGroup and WithAttrs down to that wrapped handler too. - - I like slog overall but I will say writing a correct Handler - wrapper is distinctly nontrivial. -* v0.2.0 **BREAKING CHANGE**: - * If test code panics, and a `*testing.T.Cleanup` function itself - has some sort of `.Fatal` call, the result is that the panic is - eaten. Due to [Golang issue - #49929](https://github.com/golang/go/issues/49929), there is no - way to detect this in the cleanup function because the cleanup - function is run in the wrong place to detect the panic and the - `t.Failed()` method will return false. - - Practice has revealed that this is _way_ too confusing, so I'm - removing the automatic cleanup function. Therefore, **any - slogassert.New calls need to have a `defer handler.AssertEmpty()` - manually added to retain the original behavior**. The - `AssertEmpty` function has code added to see whether it is in the - middle of a panic, and if so, it will not fatally error. (This is - in practice good anyhow because panics frequently result in the - log messages being logged but the assertions not running, so it - frequently produced spurious and confusing messages anyhow.) - - This still mangles the panic a bit, unfortunately, but the - necessary data is still there. - * I was doing a lot of work on my work laptop and had my work email - rather than my personal email, but my signing key is my personal - email. This commit signs the top of the repository correctly. - - As I mention in the version numbering section, that's what - matters; a signed commit at the top of a repository is essentially - signing the whole thing, not just that commit. So it is not - necessary to rewrite the whole repo to fix all the previous commits. -* v0.1.3: - * Add a return value to the \*Some\* methods that return how many - messages they consumed as being asserted. -* v0.1.2: - * Allow use of ints to compare against Int64, Float64, and Uint64. - - This resolves an issue where you write an AssertPrecise and use a - bare int in the source code, which the Go compiler decides is an - `int`, and then that didn't match any of the numeric types. This - adds the relevant clauses to the matchers. -* v0.1.1: - * No code changes, just screwed up tagging. -* v0.1.0: - * Fixed a major error: Somehow I completely overlooked adding the - params on a sublogger added with `.With` to the resulting log - messages. I guess I thought slog would do that for me. And this is - why v0.0.9 was only a "release candidate". - - That said, I am advancing this up the semver chain to a release - candidate. -* v0.0.9: - * Fix a locking issue in `Unasserted`, which should make this all - completely thread-safe. - * I consider this a v1.0.0. release candidate. -* v0.0.8: - * Make Unasserted return a fully independent copy of the LogMessage - so the user can't accidentally corrupt it. -* v0.0.7: - * Add Unasserted call. I've resisted this because it's kind of a - trap, but sometimes you just need it. -* v0.0.6: - * *BREAKING RELEASE*: The ability to wrap a handler is added. - This is useful for things like recording all the logs in a test - into a wrapped handler, then if the test fails, printing out the - logs as part of the test failure message. This changes the - signature on `New` and `NewWithoutCleanup`. - - To recover previous behavior, add a `nil` on the end of all such calls. -* v0.0.5: - * Add a NullHandler and NullLogger. This is not 100% on point for - the package, but pretty useful for when you need a logger but - don't need the logs, which comes up in testing a lot. -* v0.0.4: - * Handlers are responsible for resolving LogValuer values. - * This is why you don't promise no bugs. -* v0.0.3: - * Bugs! Bugs everywhere! Fewer now, but still no promises. -* v0.0.2 - * README fixup. -* v0.0.1 - * Initial release. diff --git a/pkg/slogassert/assertions.go b/pkg/slogassert/assertions.go deleted file mode 100644 index 202af8c9..00000000 --- a/pkg/slogassert/assertions.go +++ /dev/null @@ -1,485 +0,0 @@ -package slogassert - -import ( - "errors" - "fmt" - "log/slog" - "os" - "reflect" - "time" -) - -const ( - // LevelDontCare can be used in a LogMessageMatch to indicate - // that the level does not need to match. - LevelDontCare = slog.Level(-255000000) -) - -// trueOnlyonce takes an f that would potentially return true many -// times, and bounds it to the number given -func trueOnlyOnce(f func(LogMessage) bool) func(LogMessage) bool { - returnedTrue := false - - return func(l LogMessage) bool { - if returnedTrue { - return false - } - - returnedTrue = f(l) - return returnedTrue - } -} - -// Assert takes in a function that takes a recorded log message and -// indicates whether or not it is "correct" according to your tests, -// and should be removed from the slice of unasserted log -// messages. Essentially all other assertions provided are just ways -// of populating this. -// -// The passed-in function will be presented only with the remaining -// unasserted log messages at the time of the call. -func (h *Handler) Assert(f func(LogMessage) bool) int { - h.t.Helper() - root := h.root() - root.m.Lock() - defer root.m.Unlock() - newMessages := []LogMessage{} - - matchCount := 0 - for _, lm := range root.logMessages { - matched := f(lm) - if matched { - matchCount++ - } else { - newMessages = append(newMessages, lm) - } - } - - root.logMessages = newMessages - - return matchCount -} - -// Fail will print out the remaining unasserted messages and pass the -// given msg and args to t.Fatalf. This can be used in your custom -// assertions to fail them out. -func (h *Handler) Fail(msg string, args ...any) { - h.t.Helper() - // If this is used in a test as defer handler.AssertEmpty(), - // this validates that we're not currently in a panic - // recovery. If we are, we let the panic through rather than - // calling h.t.Fatalf, due to: - // - // https://github.com/golang/go/issues/49929 - // - // If that is ever fixed we can resume the original API that - // uses t.Cleanup to automatically clean up, but otherwise - // eating panics has proved to be too confusing and it's - // better to just ask people to defer handler.Cleanup if they - // want that behavior. - r := recover() - if r == nil { - for _, lm := range h.logMessages { - lm.Print(os.Stderr) - } - - h.t.Fatalf(msg, args...) - } else { - panic(r) - } -} - -// AssertEmpty asserts that all log messages have now been accounted -// for and there is nothing left. -// -// A call to this method will be automatically deferred through the -// testing system if you use New(), but you can also use New -func (h *Handler) AssertEmpty() { - h.t.Helper() - h = h.root() - h.m.Lock() - defer h.m.Unlock() - - if len(h.logMessages) == 0 { - return - } - - h.Fail("%d unasserted log message(s); see printout above", - len(h.logMessages)) -} - -// AssertSomeMessage asserts that some logging events were recorded -// with the given message. The return value is the number of matched -// messages if there were any. If there was zero, the test fails. -func (h *Handler) AssertSomeMessage(msg string) int { - h.t.Helper() - matches := h.Assert(func(lm LogMessage) bool { - return lm.Message == msg - }) - if matches == 0 { - h.Fail("No logs with message %q found", msg) - } - return matches -} - -// AssertMessage asserts a logging message recorded with the giving -// logging message. -func (h *Handler) AssertMessage(msg string) { - h.t.Helper() - matches := h.Assert(trueOnlyOnce(func(lm LogMessage) bool { - return lm.Message == msg - })) - if matches == 0 { - h.Fail("No logs with message %q found", msg) - } -} - -// AssertPrecise takes a LogMessageMatch and asserts the first log -// message that matches it. -func (h *Handler) AssertPrecise(lmm LogMessageMatch) { - h.t.Helper() - matches := h.Assert(trueOnlyOnce(func(lm LogMessage) bool { - return lmm.Matches(lm) - })) - if matches == 0 { - h.Fail("No logs matching filter were found") - } -} - -// AssertSomePrecise asserts all the messages in the log that match -// the LogMessageMatch criteria. The return value is th enumber of -// matched messages if there were any. (If there aren't any this fails -// the test.) -func (h *Handler) AssertSomePrecise(lmm LogMessageMatch) int { - h.t.Helper() - matches := h.Assert(func(lm LogMessage) bool { - return lmm.Matches(lm) - }) - if matches == 0 { - h.Fail("No logs matching filter %#v were found", lmm) - } - return matches -} - -// LogMessageMatch defines a precise message to match. -// -// The Message works as you'd expect; an equality check. It is always -// checked, so an empty message means to verify that the message -// logged was empty. -// -// If Level is LevelDontCare, the level won't be matched. Otherwise, -// it will also be an equality check. -// -// Attrs is a map of string to any. The strings will be the groups for -// the given attribute, joined together by dots. For instance, an -// ungrouped key called "url" will be "url". If it is in a "request" -// group, it will be keyed by "request.url". If that is also in a -// "webserver" group, the key will be "webserver.request.url". Any -// dots in the keys themselves will be backslash encoded, so a -// top-level key called "a.b" will be "a\.b" in this map. -// -// The value is a matcher on the attribute, which may be one of three -// things. -// -// It can be a function "func (slog.Value) bool", which will be passed -// the value. If it returns true, it is considered to match; false is -// considered to be not a match. -// -// It can be a function "func (T) bool", where "T" matches the -// concrete value behind the Kind of the slog.Value. In that case, the -// same rules apply. For KindAny, this must be precisely "func(any) -// bool"; this is done via type switching, not a lot of `reflect` -// calls, so only and exactly "func (any) bool" will work. -// -// It can be a concrete value, in which case it must be equal to the -// value contained in the attribute. Type-appropriate equality is -// used, e.g., time.Time's are compared via time.Equal. -// -// Any other value will result in an error being returned when used to -// match. -// -// AllAttrsMatch indicate whether the Attrs map must contain matches -// for all attributes in the match. If true, and there are unmatched -// attribtues in the log message, the match will fail. If false, extra -// attributes in the log message won't fail the match. -type LogMessageMatch struct { - Message string - Level slog.Level - Attrs map[string]any - AllAttrsMatch bool -} - -// Matches returnes true if the provided LogMessage satisfies -// LogMessageMatch. -func (lmm LogMessageMatch) Matches(lm LogMessage) bool { - if lmm.Message != lm.Message { - return false - } - if lmm.Level != LevelDontCare && lmm.Level != lm.Level { - return false - } - - for key, matcher := range lmm.Attrs { - val, haveVal := lm.Attrs[key] - if !haveVal { - // mandatory attribute missing - return false - } - if matchAttr(matcher, val) != nil { - return false - } - } - - if lmm.AllAttrsMatch && len(lmm.Attrs) != len(lm.Attrs) { - return false - } - - return true -} - -// Unasserted returns all the log messages that are currently -// unasserted within the slog assert. The returned result is a deep -// copy. This method does NOT assert them; after a call to this -// method, if there are any messages an AssertEmpty will still fail. -// -// It is probably superficially tempting to just use this and examine -// the result with code. However, bear in mind that using the -// assertion functions in conjuction with the default AssertEmpty on -// test cleanup already handles making sure everything is -// asserted. There's a lot of bugs easy to write with direct code -// examination. -// -// However, sometimes you just need to check the messages with code. -func (h *Handler) Unasserted() []LogMessage { - h.t.Helper() - msgs := []LogMessage{} - root := h.root() - root.m.Lock() - defer root.m.Unlock() - - for _, msg := range root.logMessages { - msgs = append(msgs, msg.clone()) - } - return msgs -} - -// Reset will simply empty out the log entirely. This can be used in -// anger to simply make tests pass, or when you legitimately have some -// logging messages you don't want to bind your tests to (for instance -// this package's own call to testing/slogtest). -func (h *Handler) Reset() { - root := h.root() - root.m.Lock() - root.logMessages = nil - root.m.Unlock() -} - -// return when the types are correct, and it just doesn't match. -var errNoMatch = errors.New("does not match") - -func matchAttr(matcher any, val slog.Value) error { - matchLogValuer, isLogValuer := matcher.(slog.LogValuer) - if isLogValuer { - matchVal := matchLogValuer.LogValue() - if !matchVal.Equal(val) { - return errNoMatch - } - return nil - } - - switch val.Kind() { - case slog.KindAny: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(any) bool: - if match(val.Any()) { - return nil - } - return errNoMatch - case any: - if reflect.DeepEqual(match, val.Any()) { - return nil - } - return errNoMatch - default: - // this can't happen but the compiler can't prove it. - return fmt.Errorf("invalid type for comparing KindAny: %T", matcher) - } - - case slog.KindBool: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(bool) bool: - if match(val.Bool()) { - return nil - } - return errNoMatch - case bool: - if match == val.Bool() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindBool: %T", matcher) - } - - case slog.KindDuration: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(time.Duration) bool: - if match(val.Duration()) { - return nil - } - return errNoMatch - case time.Duration: - if match == val.Duration() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindDuration: %T", matcher) - } - - case slog.KindFloat64: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(float64) bool: - if match(val.Float64()) { - return nil - } - return errNoMatch - case float64: - if match == val.Float64() { - return nil - } - return errNoMatch - case int: - if float64(match) == val.Float64() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindFloat64: %T", matcher) - } - - case slog.KindInt64: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(int64) bool: - if match(val.Int64()) { - return nil - } - return errNoMatch - case int64: - if match == val.Int64() { - return nil - } - return errNoMatch - case int: - if int64(match) == val.Int64() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindInt64: %T", matcher) - } - - case slog.KindString: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(string) bool: - if match(val.String()) { - return nil - } - return errNoMatch - case string: - if match == val.String() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindString: %T", matcher) - } - - case slog.KindTime: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(time.Time) bool: - if match(val.Time()) { - return nil - } - return errNoMatch - case time.Time: - if match.Equal(val.Time()) { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindTime: %T", matcher) - } - - case slog.KindUint64: - switch match := matcher.(type) { - case func(slog.Value) bool: - if match(val) { - return nil - } - return errNoMatch - case func(uint64) bool: - if match(val.Uint64()) { - return nil - } - return errNoMatch - case uint64: - if match == val.Uint64() { - return nil - } - return errNoMatch - case int: - if uint64(match) == val.Uint64() { - return nil - } - return errNoMatch - default: - return fmt.Errorf("invalid type for comparing KindUint64: %T", matcher) - } - - case slog.KindLogValuer: - return matchAttr(matcher, val.LogValuer().LogValue()) - - default: - // This means slog has apparently added a type this code is - // not familiar with and an Issue needs to be raised on - // Github with the Kind in question. Just this panic message - // should be enough to diagnose the issue. - panic(fmt.Sprintf("unknown kind in slog: %s", val.Kind())) - } -} diff --git a/pkg/slogassert/assertions_test.go b/pkg/slogassert/assertions_test.go deleted file mode 100644 index e3609bad..00000000 --- a/pkg/slogassert/assertions_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package slogassert - -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "log/slog" - "strconv" - "strings" - "time" -) - -type MatchTest struct { - Value slog.Value - GoodVal func(slog.Value) bool - BadVal func(slog.Value) bool - GoodFunc any - BadFunc any - GoodMatch any - BadMatch any -} - -func TestMatchers(t *testing.T) { - now := time.Now() - notNow := now.Add(time.Minute) - - for idx, test := range []MatchTest{ - // Any, here played by a slice of string - { - Value: slog.AnyValue([]string{}), - GoodVal: func(val slog.Value) bool { - return len(val.Any().([]string)) == 0 - }, - BadVal: func(val slog.Value) bool { - return len(val.Any().([]string)) == 1 - }, - GoodFunc: func(v any) bool { - return len(v.([]string)) == 0 - }, - BadFunc: func(v any) bool { - return len(v.([]string)) == 1 - }, - GoodMatch: []string{}, - BadMatch: []string{"nope"}, - }, - - // KindBool - { - Value: slog.BoolValue(true), - GoodVal: func(val slog.Value) bool { - return val.Bool() - }, - BadVal: func(val slog.Value) bool { - return !val.Bool() - }, - GoodFunc: func(b bool) bool { - return b - }, - BadFunc: func(b bool) bool { - return !b - }, - GoodMatch: true, - BadMatch: false, - }, - - // KindDuration - { - Value: slog.DurationValue(time.Second), - GoodVal: func(val slog.Value) bool { - return val.Duration() == time.Second - }, - BadVal: func(val slog.Value) bool { - return val.Duration() == 0 - }, - GoodFunc: func(d time.Duration) bool { - return d == time.Second - }, - BadFunc: func(d time.Duration) bool { - return d == 0 - }, - GoodMatch: time.Second, - BadMatch: time.Minute, - }, - - // KindFloat64 - { - Value: slog.Float64Value(1), - GoodVal: func(val slog.Value) bool { - return val.Float64() == 1 - }, - BadVal: func(val slog.Value) bool { - return val.Float64() == 0 - }, - GoodFunc: func(f float64) bool { - return f == 1 - }, - BadFunc: func(f float64) bool { - return f == 0 - }, - GoodMatch: float64(1), - BadMatch: float64(0), - }, - - // KindInt64 - { - Value: slog.Int64Value(1), - GoodVal: func(val slog.Value) bool { - return val.Int64() == 1 - }, - BadVal: func(val slog.Value) bool { - return val.Int64() == 0 - }, - GoodFunc: func(f int64) bool { - return f == 1 - }, - BadFunc: func(f int64) bool { - return f == 0 - }, - GoodMatch: int64(1), - BadMatch: int64(0), - }, - - // KindString - { - Value: slog.StringValue("hi!"), - GoodVal: func(val slog.Value) bool { - return val.String() == "hi!" - }, - BadVal: func(val slog.Value) bool { - return val.String() == "" - }, - GoodFunc: func(s string) bool { - return s == "hi!" - }, - BadFunc: func(s string) bool { - return s == "" - }, - GoodMatch: "hi!", - BadMatch: "", - }, - - // KindTime - { - Value: slog.TimeValue(now), - GoodVal: func(val slog.Value) bool { - return val.Time().Equal(now) - }, - BadVal: func(val slog.Value) bool { - return val.Time().Equal(notNow) - }, - GoodFunc: func(t time.Time) bool { - return t.Equal(now) - }, - BadFunc: func(t time.Time) bool { - return t.Equal(notNow) - }, - GoodMatch: now, - BadMatch: notNow, - }, - - // KindUint64 - { - Value: slog.Uint64Value(1), - GoodVal: func(val slog.Value) bool { - return val.Uint64() == 1 - }, - BadVal: func(val slog.Value) bool { - return val.Uint64() == 0 - }, - GoodFunc: func(f uint64) bool { - return f == 1 - }, - BadFunc: func(f uint64) bool { - return f == 0 - }, - GoodMatch: uint64(1), - BadMatch: uint64(0), - }, - } { - if matchAttr(test.GoodVal, test.Value) != nil { - t.Fatalf("test %d failed", idx) - } - if matchAttr(test.BadVal, test.Value) != errNoMatch { - t.Fatalf("test %d failed", idx) - } - if matchAttr(test.GoodFunc, test.Value) != nil { - fmt.Println(matchAttr(test.GoodFunc, test.Value)) - t.Fatalf("test %d failed", idx) - } - if matchAttr(test.BadFunc, test.Value) != errNoMatch { - t.Fatalf("test %d failed", idx) - } - if matchAttr(test.GoodMatch, test.Value) != nil { - t.Fatalf("test %d failed", idx) - } - if matchAttr(test.BadMatch, test.Value) != errNoMatch { - t.Fatalf("test %d failed", idx) - } - - // idx 0 is a special case; since it's the KindAny - // case, there is no value that can be passed to the - // first parameter of matchAttr that can't be - // reflect.DeepEqual'd against the test.Value to get a - // "invalid type" error. Everything else has invalid - // type possibilities. - if idx != 0 { - err := matchAttr([]int{}, test.Value) - if err == nil || !strings.Contains(err.Error(), "invalid type") { - t.Fatalf("incorrect bad type error: %v", err) - } - } - } - - if matchAttr(ValueAsString(2), slog.StringValue("2")) != nil { - t.Fatal("can't handle LogValue matchers") - } - if matchAttr(ValueAsString(2), slog.StringValue("3")) == nil { - t.Fatal("can't handle LogValue matchers") - } -} - -// A ValueAsString is an int that is also a LogValuer that returns -// itself as a string for slog. This is used for testing that the -// matching value is correct. -type ValueAsString int - -func (vas ValueAsString) LogValue() slog.Value { - return slog.StringValue(strconv.Itoa(int(vas))) -} diff --git a/pkg/slogassert/default.go b/pkg/slogassert/default.go deleted file mode 100644 index 4b0c9d1e..00000000 --- a/pkg/slogassert/default.go +++ /dev/null @@ -1,120 +0,0 @@ -package slogassert - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "log" - "log/slog" - "os" -) - -// config is used to configure the default handler, and allow the -// use of functional options. -type config struct { - level slog.Leveler - assertEmpty bool - wrapped slog.Handler -} - -// An Option allows for configuration of the default handler created -// by [NewDefault]. -type Option func(*config) - -// WithLeveler is a functional option for [NewDefault] that sets the -// minimum log level of the default handler. -// All messages below this level will be ignored. -func WithLeveler(level slog.Leveler) Option { - return func(c *config) { - c.level = level - } -} - -// WithAssertEmpty is a functional option for [NewDefault] that configures -// the handler to validated that all messages have been captured and -// asserted. -func WithAssertEmpty() Option { - return func(c *config) { - c.assertEmpty = true - } -} - -// WithWrapped is a functional option for [NewDefault] that wraps the -// generated default handler with another handler. -// If set then handle calls will be passed down to that -// handler as well. -func WithWrapped(wrapped slog.Handler) Option { - return func(c *config) { - c.wrapped = wrapped - } -} - -// NewDefault is a helper function for tests that creates a slogassert [Handler] -// and sets it as the default slog handler -// Once the test is complete it will attempt to restore the previous handler. -// -// It accepts options to customize the handler, including -// - [WithLeveler] to set the log level -// - [WithAssertEmpty] to assert that the handler is empty at the end of the test -// - [WithWrapped] to wrap the handler with another handler -// -// Example: -// -// func TestExample(t *testing.T) { -// handler := NewDefault(t, WithLeveler(slog.LevelError)) -// -// CodeUnderTest() -// -// handler.AssertMessage("expected log message") -// } -// -// This function MUST NOT be used with t.Parallel(). Doing so will cause unexpected -// results. -func NewDefault(t testing.TB, opts ...Option) *Handler { - // config used to allow for functional options - c := config{ - level: slog.LevelDebug, - assertEmpty: false, - wrapped: nil, - } - - for _, opt := range opts { - opt(&c) - } - - handler := New(t, c.level, c.wrapped) - - // take a copy of the original logger and flags so that we can restore - // once the test is complete - origLogger := slog.Default() - origFlags := log.Flags() - - t.Cleanup(func() { - // if WithAssertEmpty was set, then ensure that all messages - // have been captured. - if c.assertEmpty { - handler.AssertEmpty() - } - - // if the original logger was a default logger, then slog does not - // allow full restoration as this would cause a race condition. - // Instead, we attempt to manually restore. - // This may cause unexpected results if the output of the default - // logged had been set to something other than stdout. - // This is unlikely to have happened during test flows, and would - // also be unlikely to cause problems in tests if it has happened. - log.SetOutput(os.Stdout) - log.SetFlags(origFlags) - - // if the original logger was not a default logger, then we can - // safely restore it. - slog.SetDefault(origLogger) - }) - - // create a new logger with the slogassert handler, and set it as the - // default logger - logger := slog.New(handler) - slog.SetDefault(logger) - - // the slogassert handler is returned to allow for tests to validate log - //messages - return handler -} diff --git a/pkg/slogassert/default_test.go b/pkg/slogassert/default_test.go deleted file mode 100644 index 17b1cf97..00000000 --- a/pkg/slogassert/default_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package slogassert_test - -import ( - "context" - "log/slog" - - "github.com/CodSpeedHQ/codspeed-go/pkg/slogassert" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) - -// fakeTestingT is a testing.T used in the runnable example to demostrate usage -type fakeTestingT struct { - *testing.T -} - -func (ft *fakeTestingT) Run(_ string, f func(t *testing.T)) { - f(ft.T) -} - -var t = &fakeTestingT{ - T: &testing.T{}, -} - -// CodeUnderTest is an example function, used to demonstrate usage. -func CodeUnderTest() { - slog.ErrorContext(context.Background(), "expected log message") -} - -// -- - -func ExampleNewDefault() { - t.Run("ensure correct slog message is written", func(t *testing.T) { - // update the default logger, and then reset it at the end of the test - st := slogassert.NewDefault( - t, - slogassert.WithLeveler(slog.LevelInfo), // only capture info and above - slogassert.WithAssertEmpty(), // ensure that all messages have been captured - ) - - // ... - // run the test code - - CodeUnderTest() - - // ... - - // capture and assert that the logged message - st.AssertMessage("expected log message") - }) - - // Output: -} - -// -- - -func Test_NewDefault(t *testing.T) { - t.Run("With default slog handler", func(t *testing.T) { - defaultHandler := slogassert.NewDefault(t) - - slog.Info("This should be captured") - slog.Info("This should be ignored") - - defaultHandler.AssertMessage("This should be captured") - }) - - t.Run("With custom slog handler", func(t *testing.T) { - handler := slogassert.New(t, slog.LevelDebug, nil) - slog.SetDefault(slog.New(handler)) - - t.Run("subtest", func(t *testing.T) { - defaultHandler := slogassert.NewDefault(t) - slog.Info("This should be captured") - slog.Info("This should be ignored") - - defaultHandler.AssertMessage("This should be captured") - }) - - slog.Info("This should also be captured") - handler.AssertMessage("This should also be captured") - }) - - t.Run("With wrapped logger", func(t *testing.T) { - handler := slogassert.New(t, slog.LevelDebug, nil) - defaultHandler := slogassert.NewDefault(t, slogassert.WithWrapped(handler)) - - slog.Info("This should be captured") - - handler.AssertMessage("This should be captured") - defaultHandler.AssertMessage("This should be captured") - }) - - t.Run("With leveler", func(t *testing.T) { - defaultHandler := slogassert.NewDefault( - t, - slogassert.WithLeveler(slog.LevelInfo), - slogassert.WithAssertEmpty(), - ) - - slog.Debug("This should be ignored") - slog.Info("This should be captured") - - defaultHandler.AssertMessage("This should be captured") - }) - -} diff --git a/pkg/slogassert/null_handler.go b/pkg/slogassert/null_handler.go deleted file mode 100644 index a096dfad..00000000 --- a/pkg/slogassert/null_handler.go +++ /dev/null @@ -1,32 +0,0 @@ -package slogassert - -import ( - "context" - "log/slog" -) - -type nullHandler struct{} - -func (nh nullHandler) Enabled(_ context.Context, _ slog.Level) bool { - return false -} - -func (nh nullHandler) Handle(_ context.Context, _ slog.Record) error { - return nil -} - -func (nh nullHandler) WithAttrs(_ []slog.Attr) slog.Handler { - return nh -} - -func (nh nullHandler) WithGroup(_ string) slog.Handler { - return nh -} - -// NullHandler returns a slog.Handler that does nothing. -func NullHandler() slog.Handler { return nullHandler{} } - -// NullLogger returns a *slog.Logger pointed at a NullHandler. -func NullLogger() *slog.Logger { - return slog.New(NullHandler()) -} diff --git a/pkg/slogassert/null_handler_test.go b/pkg/slogassert/null_handler_test.go deleted file mode 100644 index ca07d78d..00000000 --- a/pkg/slogassert/null_handler_test.go +++ /dev/null @@ -1,10 +0,0 @@ -package slogassert - -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - -func TestNullHandler(t *testing.T) { - l := NullLogger() - - // Just verify this doesn't crash. - l.With("x", "y").WithGroup("nope").Debug("no") -} diff --git a/pkg/slogassert/pre-commit b/pkg/slogassert/pre-commit deleted file mode 100755 index e1379e54..00000000 --- a/pkg/slogassert/pre-commit +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# This ensures all executables build and all tests pass before a commit -# goes through. - -set -v -set -e - -go test -golangci-lint run - -echo Build succeeds. -exit 0 diff --git a/pkg/slogassert/slogassert.go b/pkg/slogassert/slogassert.go deleted file mode 100644 index f9d107f0..00000000 --- a/pkg/slogassert/slogassert.go +++ /dev/null @@ -1,322 +0,0 @@ -/* -Package slogassert provides a slog Handler that allows testing that -expected logging messages were made in your test code. - -# Normal Usage - -Normal usage looks like this: - - func TestSomething(t *testing.T) { - // This automatically registers a Cleanup function to assert - // that all log messages are accounted for. - handler := slogassert.New(t, slog.LevelWarn) - logger := slog.New(handler) - - // inject the logger into your test code and run it - - // Now start asserting things: - handler.AssertSomeOf("some log message") - - // often useful to finish up with an assertion that - // all log messages have been accounted for: - handler.AssertEmpty() - } - -A variety of assertions at varying levels of detail are available on -the Handler. -*/ -package slogassert - -import ( - "context" - "fmt" - "io" - "log/slog" - "maps" - "runtime/debug" - "sort" - "strings" - "sync" - "time" -) - -// Handler implements the slog.Handler interface, with additional -// methods for testing. -// -// All methods on this Handler are thread-safe. -type Handler struct { - // only the top-level logger should be doing the recording, - // all children loggers need to defer farther down - parent *Handler - - wrapped slog.Handler - - leveler slog.Leveler - currentGroup []string - // group -> attrs in that group, "" = default group - attrs *groupedAttrs - - m sync.Mutex - logMessages []LogMessage - - t Tester -} - -// The Tester interface defines the incoming testing interface. -// -// The standard library *testing.T and *testing.B values conform to this -// already. -// -// If your testing library doesn't have an equivalent of Helper, it is fine -// to implement it as a no-op. -type Tester interface { - Helper() - Fatalf(string, ...any) -} - -// New creates a new testing logger, logging with the given level. -// -// If wrapped is not nil, Handle calls will be passed down to that -// handler as well. -// -// It is recommended to generally call defer handler.AssertEmpty() on -// the result of this call. -func New(t Tester, leveler slog.Leveler, wrapped slog.Handler) *Handler { - if t == nil { - panic("t must not be nil for a slogtest.Handler") - } - handler := &Handler{ - leveler: leveler, - attrs: &groupedAttrs{groups: map[string]*groupedAttrs{}}, - t: t, - wrapped: wrapped, - } - return handler -} - -// WithAttrs implements slog.Handler, creating a sub-handler with the given -// hard-coded attributes. -func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler { - handler := h.child() - handler.attrs.set(h.currentGroup, attrs...) - - if h.wrapped != nil { - handler.wrapped = h.wrapped.WithAttrs(attrs) - } - - return handler -} - -// WithGroup implements slog.Handler, creating a new handler that will group -// everything into the given group. -func (h *Handler) WithGroup(name string) slog.Handler { - handler := h.child() - handler.currentGroup = append(append([]string{}, - h.currentGroup...), name) - - if h.wrapped != nil { - handler.wrapped = h.wrapped.WithGroup(name) - } - - return handler -} - -// Enabled implements slog.Handler, reporting back to slog whether or -// not the handler is enabled for this level of log message. -func (h *Handler) Enabled(_ context.Context, level slog.Level) bool { - return level >= h.leveler.Level() -} - -// Handle implements slog.Handler, recording a log message into the -// root handler. -func (h *Handler) Handle(ctx context.Context, record slog.Record) error { - lm := LogMessage{ - Message: record.Message, - Level: record.Level, - Stacktrace: string(debug.Stack()), - Attrs: map[string]slog.Value{}, - Time: record.Time, - } - - var f func(group []string, attr slog.Attr) bool - f = func(group []string, attr slog.Attr) bool { - val := attr.Value.Resolve() - switch val.Kind() { - case slog.KindGroup: - groupName := attr.Key - attrs := val.Group() - newGroups := append(append([]string{}, group...), groupName) - for _, attr := range attrs { - f(newGroups, attr) - } - - default: - lm.Attrs[encgroups(group, attr.Key)] = val - } - return true - } - - record.Attrs(func(attr slog.Attr) bool { - return f(h.currentGroup, attr) - }) - - root := h.root() - root.m.Lock() - h.attrs.runOn(f) - - root.logMessages = append(root.logMessages, lm) - root.m.Unlock() - - if h.wrapped != nil { - return h.wrapped.Handle(ctx, record) - } - - return nil -} - -func (h *Handler) root() *Handler { - for h.parent != nil { - h = h.parent - } - return h -} - -func (h *Handler) child() *Handler { - return &Handler{ - parent: h, - currentGroup: append([]string{}, h.currentGroup...), - attrs: h.attrs.clone(), - leveler: h.leveler, - wrapped: h.wrapped, - } -} - -// LogMessage is a struct for storing the log messages picked up by -// slogassert's handler. -type LogMessage struct { - Message string - Level slog.Level - Stacktrace string - // key is the slash-encoded group path to this value - Attrs map[string]slog.Value - // this package deliberately ignores this, but passing - // testing/slogtest requires us to store this - Time time.Time -} - -// Print is a default method that can dump a LogMessage out to a -// writer; this is used by slogassert to print unasserted log messages. -func (lm *LogMessage) Print(w io.Writer) { - msg := strings.Builder{} - msg.WriteString("--------\nmessage: ") - msg.WriteString(lm.Message) - msg.WriteString("\nlevel: ") - msg.WriteString(lm.Level.String()) - msg.WriteString("\nattributes:\n") - keys := []string{} - for attrKey := range lm.Attrs { - keys = append(keys, attrKey) - } - sort.Strings(keys) - for _, key := range keys { - val := lm.Attrs[key] - msg.WriteString(" ") - msg.WriteString(key) - msg.WriteString(" -> (") - msg.WriteString(val.Kind().String()) - msg.WriteString(") ") - msg.WriteString(fmt.Sprintf("%v", val.Any())) - msg.WriteString("\n") - } - msg.WriteString("\nstack trace:\n") - msg.WriteString(lm.Stacktrace) - msg.WriteString("\n") - _, _ = w.Write([]byte(msg.String())) -} - -func (lm *LogMessage) clone() LogMessage { - return LogMessage{ - Message: lm.Message, - Level: lm.Level, - Stacktrace: lm.Stacktrace, - Time: lm.Time, - Attrs: maps.Clone(lm.Attrs), - } -} - -type groupedAttrs struct { - // the attrs at this group level - attrs []slog.Attr - - // child groups - groups map[string]*groupedAttrs -} - -func (ga *groupedAttrs) set(groupkeys []string, attr ...slog.Attr) { - target := ga - for _, group := range groupkeys { - newTarget := target.groups[group] - if newTarget == nil { - target.groups[group] = &groupedAttrs{ - groups: map[string]*groupedAttrs{}, - } - newTarget = target.groups[group] - } - target = newTarget - } - - target.attrs = append(target.attrs, attr...) -} - -func (ga *groupedAttrs) clone() *groupedAttrs { - new := &groupedAttrs{ - attrs: append([]slog.Attr{}, ga.attrs...), - groups: map[string]*groupedAttrs{}, - } - for group, child := range ga.groups { - new.groups[group] = child.clone() - } - return new -} - -// should be run only under handler lock -func (ga *groupedAttrs) runOn(f func([]string, slog.Attr) bool) { - ga.runOnRecursive(nil, f) -} - -func (ga *groupedAttrs) runOnRecursive( - currGroup []string, - f func([]string, slog.Attr) bool, -) { - for _, attr := range ga.attrs { - res := f(currGroup, attr) - if !res { - return - } - } - - for group, subGa := range ga.groups { - newGroup := append(currGroup, group) - subGa.runOnRecursive(newGroup, f) - } -} - -func dotEncode(s string) string { - return strings.ReplaceAll( - strings.ReplaceAll(s, "\\", "\\\\"), - ".", - "\\.", - ) -} - -// encgroups unambiguously encodes slices into a single -// string. backslash encoding is a bit klunky, but it's so traditional -// it seems the best choice anyhow. -func encgroups(group []string, key string) string { - converted := make([]string, len(group)+1) - for i := 0; i < len(group); i++ { - converted[i] = dotEncode(group[i]) - } - converted[len(converted)-1] = dotEncode(key) - return strings.Join(converted, ".") -} diff --git a/pkg/slogassert/slogassert_test.go b/pkg/slogassert/slogassert_test.go deleted file mode 100644 index e233b48a..00000000 --- a/pkg/slogassert/slogassert_test.go +++ /dev/null @@ -1,284 +0,0 @@ -package slogassert - -import ( - "log/slog" - "reflect" - "strings" - "time" - - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - slogtest "github.com/CodSpeedHQ/codspeed-go/testing/testing/slogtest" -) - -const ( - testWarning = "test warning" - test2 = "test2" - test3 = "test3" -) - -func TestVeryBasicFunctionality(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - - sublog := log.WithGroup("test").With( - slog.String("constant", "hello"), - ) - - sublog.Warn(testWarning, - slog.Group("req", - slog.String("method", "GET"), - slog.Group("notreq", - slog.String("innotgroup", "can nest"), - ), - slog.String("url", "/url")), - slog.Int("status", 200), - slog.Duration("duration", time.Second), - ) - - if handler.AssertSomeMessage(testWarning) != 1 { - t.Fatal("incorrect number return from AssertSomeMessage") - } -} - -func TestSlogHandler(t *testing.T) { - handler := New(t, slog.LevelDebug, nil) - defer handler.AssertEmpty() - err := slogtest.TestHandler(handler, func() []map[string]any { - results := []map[string]any{} - - for _, lm := range handler.logMessages { - handler.logMessages = handler.logMessages[:0] - - result := map[string]any{ - slog.TimeKey: lm.Time, - slog.LevelKey: lm.Level, - slog.MessageKey: lm.Message, - } - results = append(results, result) - } - - // empty out the results for next time - handler.logMessages = []LogMessage{} - return results - }) - if err != nil { - t.Fatalf("incorrect handler behavior: %v", err) - } -} - -func TestAssertSomeMessage(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning) - - msgs := handler.Unasserted() - if len(msgs) != 1 { - t.Fatal("incorrect number of unasserted messages") - } - msgs[0].Time = time.Time{} - msgs[0].Stacktrace = "" - if !reflect.DeepEqual(msgs, []LogMessage{ - { - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]slog.Value{}, - }, - }) { - t.Fatal("incorrect return for Unasserted") - } - - log.Warn(testWarning) - log.Warn(testWarning) - - if handler.AssertSomeMessage(testWarning) != 3 { - t.Fatal("incorrect number returned by AssertSomeMessage") - } - // does not crash because they are all consumed -} - -func TestAssertMessage(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning) - - handler.AssertMessage(testWarning) - // does not crash because the message is consumed -} - -func TestAssertPrecise(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning, "key", "val") - - handler.AssertPrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]any{ - "key": "val", - }, - }) - - // slog upgrades ints to int64s, and then when we pass a base - // "1" in the source code to test for them the type doesn't - // match. This is quite annoying. Test that we fixed that, - // which is to say, in the Attrs map, we don't need to cast to - // int64: - log.Warn(testWarning, - "int", 1, - "float", float64(2), - "uint", uint64(3), - ) - handler.AssertPrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]any{ - "int": 1, - "float": 2, - "uint": 3, - }, - }) - - // does not crash because the message is consumed -} - -func TestReset(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning, "key", "val") - - handler.Reset() - // does not crash because the message is consumed -} - -func TestFiltering(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - - log.Warn(testWarning) - log.Warn(test2) - log.Warn(test3) - - handler.AssertMessage(test2) - handler.AssertMessage(test3) - handler.AssertMessage(testWarning) - - // does not crash because the messages were properly consumed -} - -func TestAssertSomePrecise(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning, "key", "val") - log.Warn(testWarning, "key", "val") - log.Warn(testWarning, "key", "val") - - if handler.AssertSomePrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]any{ - "key": "val", - }, - }) != 3 { - t.Fatal("incorrect number returned from AssertSomePrecise") - } - - // does not crash because the message is consumed -} - -func TestLogValuer(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - log.Warn(testWarning, - "valuer", testLogValuer{}, - slog.Group("group", "subgroup", testLogValuer{}), - ) - - handler.AssertPrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]any{ - "valuer.a": "a", - "valuer.b": "b", - "group.subgroup.a": "a", - "group.subgroup.b": "b", - }, - AllAttrsMatch: true, - }) -} - -func TestWrapping(t *testing.T) { - buf := &strings.Builder{} - wrappedHandler := slog.NewTextHandler(buf, nil) - handler := New(t, slog.LevelWarn, wrappedHandler) - defer handler.AssertEmpty() - logger := slog.New(handler) - - logger.WithGroup("test").Warn(testWarning, - "a", "b") - - handler.AssertPrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelWarn, - Attrs: map[string]any{ - "test.a": "b", - }, - AllAttrsMatch: true, - }) - - logged := buf.String() - // hack off the timestamp because it is always different - _, remainder, _ := strings.Cut(logged, " ") - if strings.TrimSpace(remainder) != `level=WARN msg="test warning" test.a=b` { - t.Fatal("did not get expected log result") - } -} - -func TestWith(t *testing.T) { - handler := New(t, slog.LevelWarn, nil) - defer handler.AssertEmpty() - log := slog.New(handler) - subLog := log.With("test_attr", "value").WithGroup("group").With("test2", "value2") - subLog.Error(testWarning) - handler.AssertPrecise(LogMessageMatch{ - Message: testWarning, - Level: slog.LevelError, - Attrs: map[string]any{ - "test_attr": "value", - "group.test2": "value2", - }, - AllAttrsMatch: true, - }) -} - -type testLogValuer struct{} - -func (t testLogValuer) LogValue() slog.Value { - return slog.GroupValue( - slog.String("a", "a"), - slog.String("b", "b"), - ) -} - -// various little assertions to cover the code -func TestCoverage(t *testing.T) { - panics(t, "New with nil", func() { New(nil, slog.LevelWarn, nil) }) -} - -func panics(t *testing.T, name string, f func()) { - defer func() { - r := recover() - if r == nil { - t.Fatalf("%s failed to panic", name) - } - }() - - f() -} From 45bb0bb3578f50ee3698203eea4bf4564a13622d Mon Sep 17 00:00:00 2001 From: not-matthias Date: Thu, 8 Jan 2026 16:16:53 +0100 Subject: [PATCH 02/13] chore: remove example-codspeed --- example-codspeed/cli/runner.go | 106 ------------------ example-codspeed/compat/quicktest_codspeed.go | 25 ----- .../compat/slogassert_codspeed.go | 24 ---- example-codspeed/fib.go | 8 -- example-codspeed/fib_codspeed.go | 51 --------- example-codspeed/go-runner.metadata | 4 - example-codspeed/go.mod | 14 --- example-codspeed/go.sum | 10 -- 8 files changed, 242 deletions(-) delete mode 100644 example-codspeed/cli/runner.go delete mode 100644 example-codspeed/compat/quicktest_codspeed.go delete mode 100644 example-codspeed/compat/slogassert_codspeed.go delete mode 100644 example-codspeed/fib.go delete mode 100644 example-codspeed/fib_codspeed.go delete mode 100644 example-codspeed/go-runner.metadata delete mode 100644 example-codspeed/go.mod delete mode 100644 example-codspeed/go.sum diff --git a/example-codspeed/cli/runner.go b/example-codspeed/cli/runner.go deleted file mode 100644 index efbea285..00000000 --- a/example-codspeed/cli/runner.go +++ /dev/null @@ -1,106 +0,0 @@ -//go:build codspeed -// +build codspeed - -package main - -import ( - "io" - "reflect" - "regexp" - "time" - - codspeed_testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - // Import parent package containing the benchmarks - example "example" - compat "example/compat" -) - -// TestDeps is an implementation of the testing.testDeps interface, -// suitable for passing to [testing.MainStart]. -// -// It is partially copied from `testing/internal/testdeps/deps.go`, and -// only implements the minimum required functionality. -type TestDeps struct{} - -func (d TestDeps) ImportPath() string { return "" } - -var matchPat string -var matchRe *regexp.Regexp - -func (TestDeps) MatchString(pat, str string) (result bool, err error) { - if matchRe == nil || matchPat != pat { - matchPat = pat - matchRe, err = regexp.Compile(matchPat) - if err != nil { - return - } - } - return matchRe.MatchString(str), nil -} - -func (d TestDeps) SetPanicOnExit0(bool) {} -func (d TestDeps) StartCPUProfile(io.Writer) error { return nil } -func (d TestDeps) StopCPUProfile() {} -func (d TestDeps) StartTestLog(io.Writer) {} -func (d TestDeps) StopTestLog() error { return nil } -func (d TestDeps) WriteProfileTo(string, io.Writer, int) error { return nil } - -type corpusEntry = struct { - Parent string - Path string - Data []byte - Values []any - Generation int - IsSeed bool -} - -func (d TestDeps) CoordinateFuzzing(fuzzTime time.Duration, fuzzN int64, minimizeTime time.Duration, minimizeN int64, parallel int, corpus []corpusEntry, types []reflect.Type, corpusDir, cacheDir string) error { - return nil -} -func (d TestDeps) RunFuzzWorker(fn func(corpusEntry) error) error { return nil } -func (d TestDeps) ReadCorpus(dir string, types []reflect.Type) ([]corpusEntry, error) { - return nil, nil -} -func (d TestDeps) CheckCorpus(vals []any, types []reflect.Type) error { - return nil -} -func (d TestDeps) ResetCoverage() {} -func (d TestDeps) SnapshotCoverage() {} -func (d TestDeps) InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { - return "", nil, nil -} - -func main() { - var tests = []codspeed_testing.InternalTest{} - var fuzzTargets = []codspeed_testing.InternalFuzzTarget{} - var examples = []codspeed_testing.InternalExample{} - var benchmarks = []codspeed_testing.InternalBenchmark{ - { - Name: "BenchmarkFibonacci10", - F: example.BenchmarkFibonacci10, - }, - { - Name: "BenchmarkFibonacci20", - F: example.BenchmarkFibonacci20, - }, - { - Name: "BenchmarkFibonacci20Parallel", - F: example.BenchmarkFibonacci20Parallel, - }, - { - Name: "BenchmarkFibonacci10Parallel", - F: example.BenchmarkFibonacci10Parallel, - }, - { - Name: "BenchmarkWithSlogAssert", - F: compat.BenchmarkWithSlogAssert, - }, { - Name: "BenchmarkQuicktest", - F: compat.BenchmarkQuicktest, - }, - } - - m := codspeed_testing.MainStart(TestDeps{}, tests, benchmarks, fuzzTargets, examples) - m.Run() -} diff --git a/example-codspeed/compat/quicktest_codspeed.go b/example-codspeed/compat/quicktest_codspeed.go deleted file mode 100644 index e270dfbb..00000000 --- a/example-codspeed/compat/quicktest_codspeed.go +++ /dev/null @@ -1,25 +0,0 @@ -package compat - -import ( - qt "github.com/CodSpeedHQ/codspeed-go/pkg/quicktest" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) - -func TestQuicktest(t *testing.T) { - t.Run("numbers", func(t *testing.T) { - c := qt.New(t) - - c.Assert("hello world", qt.Contains, "world") - c.Assert([]int{3, 5, 7, 99}, qt.Contains, 7) - c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0) - }) -} - -func BenchmarkQuicktest(b *testing.B) { - for b.Loop() { - c := qt.New(b) - c.Assert("hello world", qt.Contains, "world") - c.Assert([]int{3, 5, 7, 99}, qt.Contains, 7) - c.Assert([]int{3, 5, 8}, qt.All(qt.Not(qt.Equals)), 0) - } -} diff --git a/example-codspeed/compat/slogassert_codspeed.go b/example-codspeed/compat/slogassert_codspeed.go deleted file mode 100644 index d597628d..00000000 --- a/example-codspeed/compat/slogassert_codspeed.go +++ /dev/null @@ -1,24 +0,0 @@ -package compat - -import ( - "log/slog" - - slogassert "github.com/CodSpeedHQ/codspeed-go/pkg/slogassert" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) - -func TestWithSlogAssert(t *testing.T) { - handler := slogassert.NewDefault(t) - slog.Info("This is a test log message") - handler.AssertMessage("This is a test log message") - handler.AssertEmpty() -} - -func BenchmarkWithSlogAssert(b *testing.B) { - for b.Loop() { - handler := slogassert.NewDefault(b) - slog.Info("This is a test log message") - handler.AssertMessage("This is a test log message") - handler.AssertEmpty() - } -} diff --git a/example-codspeed/fib.go b/example-codspeed/fib.go deleted file mode 100644 index 89f515de..00000000 --- a/example-codspeed/fib.go +++ /dev/null @@ -1,8 +0,0 @@ -package example - -func fibonacci(n int) int { - if n <= 1 { - return n - } - return fibonacci(n-1) + fibonacci(n-2) -} diff --git a/example-codspeed/fib_codspeed.go b/example-codspeed/fib_codspeed.go deleted file mode 100644 index 2f5d9148..00000000 --- a/example-codspeed/fib_codspeed.go +++ /dev/null @@ -1,51 +0,0 @@ -package example - -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) - -func BenchmarkFibonacci10(b *testing.B) { - b.Run("fibonacci(10)", func(b *testing.B) { - for i := 0; i < b.N; i++ { - fibonacci(10) - } - }) - b.Run("fibonacci(20)", func(b *testing.B) { - for i := 0; i < b.N; i++ { - fibonacci(20) - } - }) - // b.RunParallel(func(b *testing.PB) { - // for b.Next() { - // fibonacci(30) - // } - // }) -} - -func BenchmarkFibonacci20(b *testing.B) { - for b.Loop() { - fibonacci(20) - } -} - -func BenchmarkFibonacci30(b *testing.B) { - for i := 0; i < b.N; i++ { - fibonacci(30) - } -} - -func BenchmarkFibonacci20Parallel(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - fibonacci(20) - } - }) -} - -func BenchmarkFibonacci10Parallel(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - fibonacci(10) - } - }) -} diff --git a/example-codspeed/go-runner.metadata b/example-codspeed/go-runner.metadata deleted file mode 100644 index a192f5fa..00000000 --- a/example-codspeed/go-runner.metadata +++ /dev/null @@ -1,4 +0,0 @@ -{ - "profile_folder": "/tmp", - "relative_package_path": "codspeed-go" -} diff --git a/example-codspeed/go.mod b/example-codspeed/go.mod deleted file mode 100644 index f0167053..00000000 --- a/example-codspeed/go.mod +++ /dev/null @@ -1,14 +0,0 @@ -module example - -go 1.24.3 - -require github.com/CodSpeedHQ/codspeed-go v0.1.2 - -require ( - github.com/google/go-cmp v0.7.0 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect -) - -replace github.com/CodSpeedHQ/codspeed-go => .. diff --git a/example-codspeed/go.sum b/example-codspeed/go.sum deleted file mode 100644 index faf8f26a..00000000 --- a/example-codspeed/go.sum +++ /dev/null @@ -1,10 +0,0 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= From 58937524f7c1a614f2f710f5a76b5c7fa3838530 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Thu, 8 Jan 2026 16:17:01 +0100 Subject: [PATCH 03/13] chore: remove testing --- .github/workflows/ci.yml | 21 - testing/capi/instrument-hooks.go | 98 - testing/capi/instrument-hooks/dist/core.c | 8637 ----------------- .../instrument-hooks/includes/callgrind.h | 124 - testing/capi/instrument-hooks/includes/core.h | 86 - .../capi/instrument-hooks/includes/valgrind.h | 7168 -------------- testing/capi/instrument-hooks/includes/zig.h | 4209 -------- testing/capi/vendor.sh | 22 - testing/fork.sh | 133 - testing/internal/bisect/bisect.go | 778 -- testing/internal/cfg/cfg.go | 74 - testing/internal/cpu/cpu.go | 267 - testing/internal/cpu/cpu.s | 6 - testing/internal/cpu/cpu_arm.go | 48 - testing/internal/cpu/cpu_arm64.go | 83 - testing/internal/cpu/cpu_arm64.s | 25 - testing/internal/cpu/cpu_arm64_android.go | 11 - testing/internal/cpu/cpu_arm64_darwin.go | 52 - testing/internal/cpu/cpu_arm64_freebsd.go | 15 - testing/internal/cpu/cpu_arm64_hwcap.go | 88 - testing/internal/cpu/cpu_arm64_linux.go | 11 - testing/internal/cpu/cpu_arm64_openbsd.go | 35 - testing/internal/cpu/cpu_arm64_other.go | 13 - testing/internal/cpu/cpu_loong64.go | 55 - testing/internal/cpu/cpu_loong64.s | 12 - testing/internal/cpu/cpu_loong64_hwcap.go | 28 - testing/internal/cpu/cpu_loong64_linux.go | 11 - testing/internal/cpu/cpu_mips.go | 10 - testing/internal/cpu/cpu_mips64x.go | 32 - testing/internal/cpu/cpu_mipsle.go | 10 - testing/internal/cpu/cpu_no_name.go | 18 - testing/internal/cpu/cpu_ppc64x.go | 35 - testing/internal/cpu/cpu_ppc64x_aix.go | 25 - testing/internal/cpu/cpu_ppc64x_linux.go | 33 - testing/internal/cpu/cpu_ppc64x_other.go | 13 - testing/internal/cpu/cpu_riscv64.go | 22 - testing/internal/cpu/cpu_riscv64_linux.go | 93 - testing/internal/cpu/cpu_riscv64_other.go | 11 - testing/internal/cpu/cpu_s390x.go | 205 - testing/internal/cpu/cpu_s390x.s | 62 - testing/internal/cpu/cpu_s390x_test.go | 63 - testing/internal/cpu/cpu_test.go | 58 - testing/internal/cpu/cpu_wasm.go | 10 - testing/internal/cpu/cpu_x86.go | 216 - testing/internal/cpu/cpu_x86.s | 43 - testing/internal/cpu/cpu_x86_test.go | 57 - testing/internal/cpu/export_test.go | 9 - testing/internal/cpu/export_x86_test.go | 11 - testing/internal/diff/diff.go | 261 - testing/internal/diff/diff_test.go | 43 - testing/internal/diff/testdata/allnew.txt | 13 - testing/internal/diff/testdata/allold.txt | 13 - testing/internal/diff/testdata/basic.txt | 35 - testing/internal/diff/testdata/dups.txt | 40 - testing/internal/diff/testdata/end.txt | 38 - testing/internal/diff/testdata/eof.txt | 9 - testing/internal/diff/testdata/eof1.txt | 18 - testing/internal/diff/testdata/eof2.txt | 18 - testing/internal/diff/testdata/long.txt | 62 - testing/internal/diff/testdata/same.txt | 5 - testing/internal/diff/testdata/start.txt | 34 - testing/internal/diff/testdata/triv.txt | 40 - testing/internal/fuzz/counters_supported.go | 21 - testing/internal/fuzz/counters_unsupported.go | 24 - testing/internal/fuzz/coverage.go | 115 - testing/internal/fuzz/encoding.go | 361 - testing/internal/fuzz/encoding_test.go | 406 - testing/internal/fuzz/fuzz.go | 1102 --- testing/internal/fuzz/mem.go | 138 - testing/internal/fuzz/minimize.go | 95 - testing/internal/fuzz/minimize_test.go | 182 - testing/internal/fuzz/mutator.go | 293 - testing/internal/fuzz/mutator_test.go | 117 - testing/internal/fuzz/mutators_byteslice.go | 313 - .../internal/fuzz/mutators_byteslice_test.go | 221 - testing/internal/fuzz/pcg.go | 139 - testing/internal/fuzz/queue.go | 71 - testing/internal/fuzz/queue_test.go | 58 - testing/internal/fuzz/sys_posix.go | 130 - testing/internal/fuzz/sys_unimplemented.go | 44 - testing/internal/fuzz/sys_windows.go | 144 - testing/internal/fuzz/trace.go | 35 - testing/internal/fuzz/worker.go | 1195 --- testing/internal/fuzz/worker_test.go | 206 - testing/internal/goarch/gengoarch.go | 60 - testing/internal/goarch/goarch.go | 62 - testing/internal/goarch/goarch_386.go | 13 - testing/internal/goarch/goarch_amd64.go | 13 - testing/internal/goarch/goarch_arm.go | 13 - testing/internal/goarch/goarch_arm64.go | 13 - testing/internal/goarch/goarch_loong64.go | 15 - testing/internal/goarch/goarch_mips.go | 13 - testing/internal/goarch/goarch_mips64.go | 13 - testing/internal/goarch/goarch_mips64le.go | 13 - testing/internal/goarch/goarch_mipsle.go | 13 - testing/internal/goarch/goarch_ppc64.go | 13 - testing/internal/goarch/goarch_ppc64le.go | 13 - testing/internal/goarch/goarch_riscv64.go | 13 - testing/internal/goarch/goarch_s390x.go | 13 - testing/internal/goarch/goarch_wasm.go | 13 - testing/internal/goarch/zgoarch_386.go | 32 - testing/internal/goarch/zgoarch_amd64.go | 32 - testing/internal/goarch/zgoarch_arm.go | 32 - testing/internal/goarch/zgoarch_arm64.go | 32 - testing/internal/goarch/zgoarch_arm64be.go | 32 - testing/internal/goarch/zgoarch_armbe.go | 32 - testing/internal/goarch/zgoarch_loong64.go | 32 - testing/internal/goarch/zgoarch_mips.go | 32 - testing/internal/goarch/zgoarch_mips64.go | 32 - testing/internal/goarch/zgoarch_mips64le.go | 32 - testing/internal/goarch/zgoarch_mips64p32.go | 32 - .../internal/goarch/zgoarch_mips64p32le.go | 32 - testing/internal/goarch/zgoarch_mipsle.go | 32 - testing/internal/goarch/zgoarch_ppc.go | 32 - testing/internal/goarch/zgoarch_ppc64.go | 32 - testing/internal/goarch/zgoarch_ppc64le.go | 32 - testing/internal/goarch/zgoarch_riscv.go | 32 - testing/internal/goarch/zgoarch_riscv64.go | 32 - testing/internal/goarch/zgoarch_s390.go | 32 - testing/internal/goarch/zgoarch_s390x.go | 32 - testing/internal/goarch/zgoarch_sparc.go | 32 - testing/internal/goarch/zgoarch_sparc64.go | 32 - testing/internal/goarch/zgoarch_wasm.go | 32 - testing/internal/godebug/godebug.go | 316 - testing/internal/godebug/godebug_test.go | 193 - testing/internal/godebugs/godebugs_test.go | 95 - testing/internal/godebugs/table.go | 99 - testing/internal/platform/supported.go | 288 - testing/internal/platform/zosarch.go | 116 - testing/internal/platform/zosarch_test.go | 109 - testing/internal/race/doc.go | 11 - testing/internal/race/norace.go | 55 - testing/internal/race/race.go | 57 - testing/internal/synctest/synctest.go | 118 - testing/internal/synctest/synctest_test.go | 930 -- .../internal/syscall/windows/at_windows.go | 598 -- .../syscall/windows/at_windows_test.go | 58 - .../syscall/windows/exec_windows_test.go | 140 - .../syscall/windows/memory_windows.go | 24 - testing/internal/syscall/windows/mksyscall.go | 9 - .../internal/syscall/windows/net_windows.go | 30 - .../syscall/windows/nonblocking_windows.go | 21 - .../internal/syscall/windows/psapi_windows.go | 20 - .../syscall/windows/registry/export_test.go | 11 - .../internal/syscall/windows/registry/key.go | 168 - .../syscall/windows/registry/mksyscall.go | 9 - .../syscall/windows/registry/registry_test.go | 652 -- .../syscall/windows/registry/syscall.go | 27 - .../syscall/windows/registry/value.go | 369 - .../windows/registry/zsyscall_windows.go | 107 - .../syscall/windows/reparse_windows.go | 94 - .../syscall/windows/security_windows.go | 264 - .../syscall/windows/string_windows.go | 32 - .../syscall/windows/symlink_windows.go | 43 - .../syscall/windows/syscall_windows.go | 579 -- .../internal/syscall/windows/sysdll/sysdll.go | 30 - .../internal/syscall/windows/types_windows.go | 267 - .../syscall/windows/version_windows.go | 138 - .../syscall/windows/version_windows_test.go | 31 - .../syscall/windows/zsyscall_windows.go | 632 -- testing/internal/sysinfo/cpuinfo_bsd.go | 14 - testing/internal/sysinfo/cpuinfo_linux.go | 75 - testing/internal/sysinfo/cpuinfo_stub.go | 11 - testing/internal/sysinfo/export_test.go | 7 - testing/internal/sysinfo/sysinfo.go | 24 - testing/internal/sysinfo/sysinfo_test.go | 15 - testing/internal/testenv/exec.go | 242 - testing/internal/testenv/noopt.go | 12 - testing/internal/testenv/opt.go | 12 - testing/internal/testenv/testenv.go | 543 -- testing/internal/testenv/testenv_notunix.go | 21 - testing/internal/testenv/testenv_notwin.go | 47 - testing/internal/testenv/testenv_test.go | 208 - testing/internal/testenv/testenv_unix.go | 43 - testing/internal/testenv/testenv_windows.go | 32 - testing/internal/testlog/exit.go | 45 - testing/internal/testlog/log.go | 68 - testing/internal/txtar/archive.go | 140 - testing/patches/benchmark.patch | 445 - .../benchmark_benchmarkers_bloop.patch | 40 - .../benchmark_remove_codspeed_folder.patch | 14 - .../benchmark_savemeasurement_bug.patch | 37 - .../benchmark_stopbenchmark_fail.patch | 22 - .../benchmark_stoptimer_mitigation.patch | 78 - testing/patches/internal_race.patch | 69 - testing/patches/synctest.patch | 79 - testing/patches/testfs.patch | 40 - testing/patches/testing.patch | 16 - testing/testing/allocs.go | 48 - testing/testing/allocs_test.go | 29 - testing/testing/benchmark.go | 1296 --- testing/testing/benchmark_test.go | 244 - testing/testing/codspeed.go | 103 - testing/testing/cover.go | 37 - testing/testing/example.go | 98 - testing/testing/example_loop_test.go | 48 - testing/testing/export_test.go | 13 - testing/testing/flag_test.go | 85 - testing/testing/fstest/mapfs.go | 340 - testing/testing/fstest/mapfs_test.go | 125 - testing/testing/fstest/testfs.go | 625 -- testing/testing/fstest/testfs_readlinkfs.go | 25 - .../fstest/testfs_readlinkfs_compat.go | 9 - testing/testing/fstest/testfs_test.go | 120 - testing/testing/fuzz.go | 745 -- testing/testing/helper_test.go | 104 - testing/testing/helperfuncs_test.go | 124 - testing/testing/internal/testdeps/deps.go | 240 - testing/testing/iotest/example_test.go | 22 - testing/testing/iotest/logger.go | 54 - testing/testing/iotest/logger_test.go | 153 - testing/testing/iotest/reader.go | 268 - testing/testing/iotest/reader_test.go | 261 - testing/testing/iotest/writer.go | 35 - testing/testing/iotest/writer_test.go | 39 - testing/testing/loop_test.go | 154 - testing/testing/match.go | 317 - testing/testing/match_test.go | 263 - testing/testing/newcover.go | 59 - testing/testing/panic_test.go | 286 - testing/testing/quick/quick.go | 385 - testing/testing/quick/quick_test.go | 327 - testing/testing/run_example.go | 66 - testing/testing/run_example_wasm.go | 76 - testing/testing/slogtest/example_test.go | 44 - testing/testing/slogtest/run_test.go | 31 - testing/testing/slogtest/slogtest.go | 391 - testing/testing/sub_test.go | 1268 --- testing/testing/synctest/example_test.go | 160 - testing/testing/synctest/helper_test.go | 15 - testing/testing/synctest/run.go | 16 - testing/testing/synctest/synctest.go | 305 - testing/testing/synctest/synctest_test.go | 190 - testing/testing/testing.go | 2730 ------ testing/testing/testing.go.orig | 2725 ------ testing/testing/testing_other.go | 31 - testing/testing/testing_test.go | 1079 -- testing/testing/testing_windows.go | 70 - testing/testing/testing_windows_test.go | 25 - 239 files changed, 55669 deletions(-) delete mode 100644 testing/capi/instrument-hooks.go delete mode 100644 testing/capi/instrument-hooks/dist/core.c delete mode 100644 testing/capi/instrument-hooks/includes/callgrind.h delete mode 100644 testing/capi/instrument-hooks/includes/core.h delete mode 100644 testing/capi/instrument-hooks/includes/valgrind.h delete mode 100644 testing/capi/instrument-hooks/includes/zig.h delete mode 100755 testing/capi/vendor.sh delete mode 100755 testing/fork.sh delete mode 100644 testing/internal/bisect/bisect.go delete mode 100644 testing/internal/cfg/cfg.go delete mode 100644 testing/internal/cpu/cpu.go delete mode 100644 testing/internal/cpu/cpu.s delete mode 100644 testing/internal/cpu/cpu_arm.go delete mode 100644 testing/internal/cpu/cpu_arm64.go delete mode 100644 testing/internal/cpu/cpu_arm64.s delete mode 100644 testing/internal/cpu/cpu_arm64_android.go delete mode 100644 testing/internal/cpu/cpu_arm64_darwin.go delete mode 100644 testing/internal/cpu/cpu_arm64_freebsd.go delete mode 100644 testing/internal/cpu/cpu_arm64_hwcap.go delete mode 100644 testing/internal/cpu/cpu_arm64_linux.go delete mode 100644 testing/internal/cpu/cpu_arm64_openbsd.go delete mode 100644 testing/internal/cpu/cpu_arm64_other.go delete mode 100644 testing/internal/cpu/cpu_loong64.go delete mode 100644 testing/internal/cpu/cpu_loong64.s delete mode 100644 testing/internal/cpu/cpu_loong64_hwcap.go delete mode 100644 testing/internal/cpu/cpu_loong64_linux.go delete mode 100644 testing/internal/cpu/cpu_mips.go delete mode 100644 testing/internal/cpu/cpu_mips64x.go delete mode 100644 testing/internal/cpu/cpu_mipsle.go delete mode 100644 testing/internal/cpu/cpu_no_name.go delete mode 100644 testing/internal/cpu/cpu_ppc64x.go delete mode 100644 testing/internal/cpu/cpu_ppc64x_aix.go delete mode 100644 testing/internal/cpu/cpu_ppc64x_linux.go delete mode 100644 testing/internal/cpu/cpu_ppc64x_other.go delete mode 100644 testing/internal/cpu/cpu_riscv64.go delete mode 100644 testing/internal/cpu/cpu_riscv64_linux.go delete mode 100644 testing/internal/cpu/cpu_riscv64_other.go delete mode 100644 testing/internal/cpu/cpu_s390x.go delete mode 100644 testing/internal/cpu/cpu_s390x.s delete mode 100644 testing/internal/cpu/cpu_s390x_test.go delete mode 100644 testing/internal/cpu/cpu_test.go delete mode 100644 testing/internal/cpu/cpu_wasm.go delete mode 100644 testing/internal/cpu/cpu_x86.go delete mode 100644 testing/internal/cpu/cpu_x86.s delete mode 100644 testing/internal/cpu/cpu_x86_test.go delete mode 100644 testing/internal/cpu/export_test.go delete mode 100644 testing/internal/cpu/export_x86_test.go delete mode 100644 testing/internal/diff/diff.go delete mode 100644 testing/internal/diff/diff_test.go delete mode 100644 testing/internal/diff/testdata/allnew.txt delete mode 100644 testing/internal/diff/testdata/allold.txt delete mode 100644 testing/internal/diff/testdata/basic.txt delete mode 100644 testing/internal/diff/testdata/dups.txt delete mode 100644 testing/internal/diff/testdata/end.txt delete mode 100644 testing/internal/diff/testdata/eof.txt delete mode 100644 testing/internal/diff/testdata/eof1.txt delete mode 100644 testing/internal/diff/testdata/eof2.txt delete mode 100644 testing/internal/diff/testdata/long.txt delete mode 100644 testing/internal/diff/testdata/same.txt delete mode 100644 testing/internal/diff/testdata/start.txt delete mode 100644 testing/internal/diff/testdata/triv.txt delete mode 100644 testing/internal/fuzz/counters_supported.go delete mode 100644 testing/internal/fuzz/counters_unsupported.go delete mode 100644 testing/internal/fuzz/coverage.go delete mode 100644 testing/internal/fuzz/encoding.go delete mode 100644 testing/internal/fuzz/encoding_test.go delete mode 100644 testing/internal/fuzz/fuzz.go delete mode 100644 testing/internal/fuzz/mem.go delete mode 100644 testing/internal/fuzz/minimize.go delete mode 100644 testing/internal/fuzz/minimize_test.go delete mode 100644 testing/internal/fuzz/mutator.go delete mode 100644 testing/internal/fuzz/mutator_test.go delete mode 100644 testing/internal/fuzz/mutators_byteslice.go delete mode 100644 testing/internal/fuzz/mutators_byteslice_test.go delete mode 100644 testing/internal/fuzz/pcg.go delete mode 100644 testing/internal/fuzz/queue.go delete mode 100644 testing/internal/fuzz/queue_test.go delete mode 100644 testing/internal/fuzz/sys_posix.go delete mode 100644 testing/internal/fuzz/sys_unimplemented.go delete mode 100644 testing/internal/fuzz/sys_windows.go delete mode 100644 testing/internal/fuzz/trace.go delete mode 100644 testing/internal/fuzz/worker.go delete mode 100644 testing/internal/fuzz/worker_test.go delete mode 100644 testing/internal/goarch/gengoarch.go delete mode 100644 testing/internal/goarch/goarch.go delete mode 100644 testing/internal/goarch/goarch_386.go delete mode 100644 testing/internal/goarch/goarch_amd64.go delete mode 100644 testing/internal/goarch/goarch_arm.go delete mode 100644 testing/internal/goarch/goarch_arm64.go delete mode 100644 testing/internal/goarch/goarch_loong64.go delete mode 100644 testing/internal/goarch/goarch_mips.go delete mode 100644 testing/internal/goarch/goarch_mips64.go delete mode 100644 testing/internal/goarch/goarch_mips64le.go delete mode 100644 testing/internal/goarch/goarch_mipsle.go delete mode 100644 testing/internal/goarch/goarch_ppc64.go delete mode 100644 testing/internal/goarch/goarch_ppc64le.go delete mode 100644 testing/internal/goarch/goarch_riscv64.go delete mode 100644 testing/internal/goarch/goarch_s390x.go delete mode 100644 testing/internal/goarch/goarch_wasm.go delete mode 100644 testing/internal/goarch/zgoarch_386.go delete mode 100644 testing/internal/goarch/zgoarch_amd64.go delete mode 100644 testing/internal/goarch/zgoarch_arm.go delete mode 100644 testing/internal/goarch/zgoarch_arm64.go delete mode 100644 testing/internal/goarch/zgoarch_arm64be.go delete mode 100644 testing/internal/goarch/zgoarch_armbe.go delete mode 100644 testing/internal/goarch/zgoarch_loong64.go delete mode 100644 testing/internal/goarch/zgoarch_mips.go delete mode 100644 testing/internal/goarch/zgoarch_mips64.go delete mode 100644 testing/internal/goarch/zgoarch_mips64le.go delete mode 100644 testing/internal/goarch/zgoarch_mips64p32.go delete mode 100644 testing/internal/goarch/zgoarch_mips64p32le.go delete mode 100644 testing/internal/goarch/zgoarch_mipsle.go delete mode 100644 testing/internal/goarch/zgoarch_ppc.go delete mode 100644 testing/internal/goarch/zgoarch_ppc64.go delete mode 100644 testing/internal/goarch/zgoarch_ppc64le.go delete mode 100644 testing/internal/goarch/zgoarch_riscv.go delete mode 100644 testing/internal/goarch/zgoarch_riscv64.go delete mode 100644 testing/internal/goarch/zgoarch_s390.go delete mode 100644 testing/internal/goarch/zgoarch_s390x.go delete mode 100644 testing/internal/goarch/zgoarch_sparc.go delete mode 100644 testing/internal/goarch/zgoarch_sparc64.go delete mode 100644 testing/internal/goarch/zgoarch_wasm.go delete mode 100644 testing/internal/godebug/godebug.go delete mode 100644 testing/internal/godebug/godebug_test.go delete mode 100644 testing/internal/godebugs/godebugs_test.go delete mode 100644 testing/internal/godebugs/table.go delete mode 100644 testing/internal/platform/supported.go delete mode 100644 testing/internal/platform/zosarch.go delete mode 100644 testing/internal/platform/zosarch_test.go delete mode 100644 testing/internal/race/doc.go delete mode 100644 testing/internal/race/norace.go delete mode 100644 testing/internal/race/race.go delete mode 100644 testing/internal/synctest/synctest.go delete mode 100644 testing/internal/synctest/synctest_test.go delete mode 100644 testing/internal/syscall/windows/at_windows.go delete mode 100644 testing/internal/syscall/windows/at_windows_test.go delete mode 100644 testing/internal/syscall/windows/exec_windows_test.go delete mode 100644 testing/internal/syscall/windows/memory_windows.go delete mode 100644 testing/internal/syscall/windows/mksyscall.go delete mode 100644 testing/internal/syscall/windows/net_windows.go delete mode 100644 testing/internal/syscall/windows/nonblocking_windows.go delete mode 100644 testing/internal/syscall/windows/psapi_windows.go delete mode 100644 testing/internal/syscall/windows/registry/export_test.go delete mode 100644 testing/internal/syscall/windows/registry/key.go delete mode 100644 testing/internal/syscall/windows/registry/mksyscall.go delete mode 100644 testing/internal/syscall/windows/registry/registry_test.go delete mode 100644 testing/internal/syscall/windows/registry/syscall.go delete mode 100644 testing/internal/syscall/windows/registry/value.go delete mode 100644 testing/internal/syscall/windows/registry/zsyscall_windows.go delete mode 100644 testing/internal/syscall/windows/reparse_windows.go delete mode 100644 testing/internal/syscall/windows/security_windows.go delete mode 100644 testing/internal/syscall/windows/string_windows.go delete mode 100644 testing/internal/syscall/windows/symlink_windows.go delete mode 100644 testing/internal/syscall/windows/syscall_windows.go delete mode 100644 testing/internal/syscall/windows/sysdll/sysdll.go delete mode 100644 testing/internal/syscall/windows/types_windows.go delete mode 100644 testing/internal/syscall/windows/version_windows.go delete mode 100644 testing/internal/syscall/windows/version_windows_test.go delete mode 100644 testing/internal/syscall/windows/zsyscall_windows.go delete mode 100644 testing/internal/sysinfo/cpuinfo_bsd.go delete mode 100644 testing/internal/sysinfo/cpuinfo_linux.go delete mode 100644 testing/internal/sysinfo/cpuinfo_stub.go delete mode 100644 testing/internal/sysinfo/export_test.go delete mode 100644 testing/internal/sysinfo/sysinfo.go delete mode 100644 testing/internal/sysinfo/sysinfo_test.go delete mode 100644 testing/internal/testenv/exec.go delete mode 100644 testing/internal/testenv/noopt.go delete mode 100644 testing/internal/testenv/opt.go delete mode 100644 testing/internal/testenv/testenv.go delete mode 100644 testing/internal/testenv/testenv_notunix.go delete mode 100644 testing/internal/testenv/testenv_notwin.go delete mode 100644 testing/internal/testenv/testenv_test.go delete mode 100644 testing/internal/testenv/testenv_unix.go delete mode 100644 testing/internal/testenv/testenv_windows.go delete mode 100644 testing/internal/testlog/exit.go delete mode 100644 testing/internal/testlog/log.go delete mode 100644 testing/internal/txtar/archive.go delete mode 100644 testing/patches/benchmark.patch delete mode 100644 testing/patches/benchmark_benchmarkers_bloop.patch delete mode 100644 testing/patches/benchmark_remove_codspeed_folder.patch delete mode 100644 testing/patches/benchmark_savemeasurement_bug.patch delete mode 100644 testing/patches/benchmark_stopbenchmark_fail.patch delete mode 100644 testing/patches/benchmark_stoptimer_mitigation.patch delete mode 100644 testing/patches/internal_race.patch delete mode 100644 testing/patches/synctest.patch delete mode 100644 testing/patches/testfs.patch delete mode 100644 testing/patches/testing.patch delete mode 100644 testing/testing/allocs.go delete mode 100644 testing/testing/allocs_test.go delete mode 100644 testing/testing/benchmark.go delete mode 100644 testing/testing/benchmark_test.go delete mode 100644 testing/testing/codspeed.go delete mode 100644 testing/testing/cover.go delete mode 100644 testing/testing/example.go delete mode 100644 testing/testing/example_loop_test.go delete mode 100644 testing/testing/export_test.go delete mode 100644 testing/testing/flag_test.go delete mode 100644 testing/testing/fstest/mapfs.go delete mode 100644 testing/testing/fstest/mapfs_test.go delete mode 100644 testing/testing/fstest/testfs.go delete mode 100644 testing/testing/fstest/testfs_readlinkfs.go delete mode 100644 testing/testing/fstest/testfs_readlinkfs_compat.go delete mode 100644 testing/testing/fstest/testfs_test.go delete mode 100644 testing/testing/fuzz.go delete mode 100644 testing/testing/helper_test.go delete mode 100644 testing/testing/helperfuncs_test.go delete mode 100644 testing/testing/internal/testdeps/deps.go delete mode 100644 testing/testing/iotest/example_test.go delete mode 100644 testing/testing/iotest/logger.go delete mode 100644 testing/testing/iotest/logger_test.go delete mode 100644 testing/testing/iotest/reader.go delete mode 100644 testing/testing/iotest/reader_test.go delete mode 100644 testing/testing/iotest/writer.go delete mode 100644 testing/testing/iotest/writer_test.go delete mode 100644 testing/testing/loop_test.go delete mode 100644 testing/testing/match.go delete mode 100644 testing/testing/match_test.go delete mode 100644 testing/testing/newcover.go delete mode 100644 testing/testing/panic_test.go delete mode 100644 testing/testing/quick/quick.go delete mode 100644 testing/testing/quick/quick_test.go delete mode 100644 testing/testing/run_example.go delete mode 100644 testing/testing/run_example_wasm.go delete mode 100644 testing/testing/slogtest/example_test.go delete mode 100644 testing/testing/slogtest/run_test.go delete mode 100644 testing/testing/slogtest/slogtest.go delete mode 100644 testing/testing/sub_test.go delete mode 100644 testing/testing/synctest/example_test.go delete mode 100644 testing/testing/synctest/helper_test.go delete mode 100644 testing/testing/synctest/run.go delete mode 100644 testing/testing/synctest/synctest.go delete mode 100644 testing/testing/synctest/synctest_test.go delete mode 100644 testing/testing/testing.go delete mode 100644 testing/testing/testing.go.orig delete mode 100644 testing/testing/testing_other.go delete mode 100644 testing/testing/testing_test.go delete mode 100644 testing/testing/testing_windows.go delete mode 100644 testing/testing/testing_windows_test.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d33f852c..9bff0687 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,26 +43,6 @@ jobs: env: CODSPEED_GO_PKG_VERSION: ${{ github.head_ref || github.ref_name }} - - verify-fork-scripts: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: actions/setup-go@v5 - - uses: pre-commit/action@v3.0.1 - - - name: Run fork.sh scripts and verify no diffs - run: | - cd testing - ./fork.sh 1.25.4 - cd .. - - if ! git diff --exit-code testing/ > /dev/null 2>&1; then - exit 1 - fi - compat-integration-test-walltime: runs-on: codspeed-macro strategy: @@ -119,7 +99,6 @@ jobs: needs: - lint - tests - - verify-fork-scripts - compat-integration-test-walltime - go-runner-benchmarks steps: diff --git a/testing/capi/instrument-hooks.go b/testing/capi/instrument-hooks.go deleted file mode 100644 index 7e636eb4..00000000 --- a/testing/capi/instrument-hooks.go +++ /dev/null @@ -1,98 +0,0 @@ -package capi - -/* -#cgo CFLAGS: -I${SRCDIR}/instrument-hooks/includes -Wno-format -Wno-format-security -#include "instrument-hooks/dist/core.c" - -#define MARKER_TYPE_BENCHMARK_START c_MARKER_TYPE_BENCHMARK_START__249 -#define MARKER_TYPE_BENCHMARK_END c_MARKER_TYPE_BENCHMARK_END__250 -typedef struct instruments_root_InstrumentHooks__547 InstrumentHooks; -*/ -import "C" -import ( - "os" - "runtime" - "unsafe" -) - -// This will be set in the go-runner -var integrationVersion = "dev" - -type InstrumentHooks struct { - hooks *C.InstrumentHooks -} - -func NewInstrumentHooks() *InstrumentHooks { - inst := &InstrumentHooks{ - hooks: C.instrument_hooks_init(), - } - runtime.SetFinalizer(inst, (*InstrumentHooks).cleanup) - inst.SetIntegration("codspeed-go", integrationVersion) - return inst -} - -func (i *InstrumentHooks) Close() { - if i.hooks != nil { - C.instrument_hooks_deinit(i.hooks) - i.hooks = nil - runtime.SetFinalizer(i, nil) - } -} - -func (i *InstrumentHooks) cleanup() { - i.Close() -} - -func (i *InstrumentHooks) SetIntegration(name, version string) { - if i.hooks == nil { - return - } - nameC := C.CString(name) - versionC := C.CString(version) - defer C.free(unsafe.Pointer(nameC)) - defer C.free(unsafe.Pointer(versionC)) - - C.instrument_hooks_set_integration(i.hooks, (*C.uint8_t)(unsafe.Pointer(nameC)), (*C.uint8_t)(unsafe.Pointer(versionC))) -} - -func (i *InstrumentHooks) StartBenchmark() { - if i.hooks != nil { - C.instrument_hooks_start_benchmark(i.hooks) - } -} - -func (i *InstrumentHooks) StopBenchmark() { - if i.hooks != nil { - C.instrument_hooks_stop_benchmark(i.hooks) - } -} - -func (i *InstrumentHooks) SetExecutedBenchmark(pid uint32, name string) { - if i.hooks == nil { - return - } - nameC := C.CString(name) - defer C.free(unsafe.Pointer(nameC)) - - C.instrument_hooks_set_executed_benchmark(i.hooks, C.uint(pid), (*C.uint8_t)(unsafe.Pointer(nameC))) -} - -func (i *InstrumentHooks) IsInstrumented() bool { - if i.hooks == nil { - return false - } - return bool(C.instrument_hooks_is_instrumented(i.hooks)) -} - -func CurrentTimestamp() uint64 { - return uint64(C.instrument_hooks_current_timestamp()) -} - -func (i *InstrumentHooks) AddBenchmarkTimestamps(startTimestamp, endTimestamp uint64) { - if i.hooks == nil { - return - } - pid := uint32(os.Getpid()) - C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.MARKER_TYPE_BENCHMARK_START, C.uint64_t(startTimestamp)) - C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.MARKER_TYPE_BENCHMARK_END, C.uint64_t(endTimestamp)) -} diff --git a/testing/capi/instrument-hooks/dist/core.c b/testing/capi/instrument-hooks/dist/core.c deleted file mode 100644 index 949038f9..00000000 --- a/testing/capi/instrument-hooks/dist/core.c +++ /dev/null @@ -1,8637 +0,0 @@ -// This file is generated by scripts/release.py -// Do not edit it manually. -#if defined(_WIN32) || defined(__APPLE__) -// Stub implementations - instrumentation not supported on Windows/macOS -#include -#include - -typedef struct InstrumentHooks { - char reserved; -} InstrumentHooks; - -InstrumentHooks* instrument_hooks_init() { - static InstrumentHooks instance = {}; - return &instance; -} - -void instrument_hooks_deinit(InstrumentHooks* hooks) {} - -bool instrument_hooks_is_instrumented(InstrumentHooks* hooks) { return false; } - -uint8_t instrument_hooks_start_benchmark(InstrumentHooks* hooks) { return 0; } - -uint8_t instrument_hooks_stop_benchmark(InstrumentHooks* hooks) { return 0; } - -uint8_t instrument_hooks_set_executed_benchmark(InstrumentHooks* hooks, - uint32_t pid, const char* uri) { - return 0; -} - -// Deprecated: use instrument_hooks_set_executed_benchmark instead -uint8_t instrument_hooks_executed_benchmark(InstrumentHooks* hooks, - uint32_t pid, const char* uri) { - return 0; -} - -uint8_t instrument_hooks_set_integration(InstrumentHooks* hooks, - const char* name, - const char* version) { - return 0; -} - -void instrument_hooks_set_feature(InstrumentHooks* hooks, uint64_t feature, - bool enabled) {} - -uint64_t instrument_hooks_current_timestamp() { return 0; } - -uint8_t instrument_hooks_add_marker(InstrumentHooks* hooks, uint32_t pid, - uint8_t marker_type, uint64_t timestamp) { - return 0; -} - -#else -#define ZIG_TARGET_MAX_INT_ALIGNMENT 16 -#include "zig.h" -struct anon__lazy_57 { - uint8_t const *ptr; - uintptr_t len; -}; -struct fs_File__608; -typedef struct anon__lazy_74 nav__1074_39; -typedef struct anon__lazy_57 nav__1074_41; -struct fs_File__608 { - int32_t handle; -}; -struct anon__lazy_74 { - struct fs_File__608 payload; - uint16_t error; -}; -struct fs_File_OpenFlags__1858; -struct fs_File_OpenFlags__1858 { - uint8_t mode; - uint8_t lock; - bool lock_nonblocking; - bool allow_ctty; -}; -struct fifo_UnixPipe_Writer__600; -typedef struct anon__lazy_82 nav__1076_39; -struct mem_Allocator__565; -typedef struct anon__lazy_57 nav__1076_42; -struct mem_Allocator_VTable__568; -struct mem_Allocator__565 { - void *ptr; - struct mem_Allocator_VTable__568 const *vtable; -}; -struct fifo_UnixPipe_Writer__600 { - struct mem_Allocator__565 allocator; - struct fs_File__608 file; -}; -struct anon__lazy_82 { - struct fifo_UnixPipe_Writer__600 payload; - uint16_t error; -}; -typedef struct anon__lazy_74 nav__1076_54; -struct fifo_UnixPipe_Reader__602; -typedef struct anon__lazy_93 nav__1075_39; -typedef struct anon__lazy_57 nav__1075_42; -struct fifo_UnixPipe_Reader__602 { - struct mem_Allocator__565 allocator; - struct fs_File__608 file; -}; -struct anon__lazy_93 { - struct fifo_UnixPipe_Reader__602 payload; - uint16_t error; -}; -typedef struct anon__lazy_74 nav__1075_54; -struct instruments_perf_PerfInstrument__559; -typedef struct anon__lazy_99 nav__751_39; -struct instruments_perf_PerfInstrument__559 { - struct mem_Allocator__565 allocator; - struct fifo_UnixPipe_Writer__600 writer; - struct fifo_UnixPipe_Reader__602 reader; -}; -struct anon__lazy_99 { - struct instruments_perf_PerfInstrument__559 payload; - uint16_t error; -}; -typedef struct anon__lazy_57 nav__751_59; -typedef struct anon__lazy_82 nav__751_61; -typedef struct anon__lazy_93 nav__751_66; -struct instruments_root_InstrumentHooks__547; -typedef struct anon__lazy_110 nav__726_39; -struct instruments_valgrind_ValgrindInstrument__554; -struct instruments_valgrind_ValgrindInstrument__554 { - struct mem_Allocator__565 allocator; -}; -struct instruments_root_InstrumentHooks__547 { - union { - struct instruments_valgrind_ValgrindInstrument__554 valgrind; - struct instruments_perf_PerfInstrument__559 perf; - } payload; - uint8_t tag; -}; -struct anon__lazy_110 { - struct instruments_root_InstrumentHooks__547 payload; - uint16_t error; -}; -typedef struct anon__lazy_99 nav__726_60; -struct shared_Command__1946; -struct shared_Command__struct_1949__1949; -typedef struct anon__lazy_57 nav__1080_44; -struct shared_Command__struct_1949__1949 { - struct anon__lazy_57 uri; - uint32_t pid; -}; -struct shared_Command__struct_1950__1950; -struct shared_Command__struct_1950__1950 { - struct anon__lazy_57 name; - struct anon__lazy_57 version; -}; -struct shared_Command__struct_1951__1951; -struct shared_MarkerType__1953; -struct shared_MarkerType__1953 { - union { - uint64_t SampleStart; - uint64_t SampleEnd; - uint64_t BenchmarkStart; - uint64_t BenchmarkEnd; - } payload; - uint8_t tag; -}; -struct shared_Command__struct_1951__1951 { - struct shared_MarkerType__1953 marker; - uint32_t pid; -}; -struct shared_Command__1946 { - union { - struct shared_Command__struct_1949__1949 ExecutedBenchmark; - struct shared_Command__struct_1950__1950 SetIntegration; - struct shared_Command__struct_1951__1951 AddMarker; - uint64_t SetVersion; - } payload; - uint8_t tag; -}; -struct array_list_ArrayListAligned_28u8_2cnull_29__1974; -typedef struct anon__lazy_134 nav__1080_60; -struct anon__lazy_134 { - uint8_t *ptr; - uintptr_t len; -}; -struct array_list_ArrayListAligned_28u8_2cnull_29__1974 { - struct anon__lazy_134 items; - uintptr_t capacity; - struct mem_Allocator__565 allocator; -}; -struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005; -struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *context; -}; -typedef struct anon__lazy_143 nav__4173_38; -struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201; -struct anon__lazy_143 { - uint32_t payload; - uint16_t error; -}; -struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178; -struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *context; -}; -struct io_Reader__2337; -typedef struct anon__lazy_155 nav__4173_50; -typedef struct anon__lazy_134 nav__4173_52; -struct io_Reader__2337 { - void const *context; - struct anon__lazy_155 (*readFn)(void const *, struct anon__lazy_134); -}; -struct anon__lazy_155 { - uintptr_t payload; - uint16_t error; -}; -typedef struct anon__lazy_165 nav__4173_64; -struct anon__lazy_165 { - uint16_t error; - uint8_t payload[4]; -}; -typedef struct anon__lazy_143 nav__4172_38; -typedef struct anon__lazy_134 nav__4215_39; -typedef struct anon__lazy_169 nav__4215_40; -struct anon__lazy_169 { - struct anon__lazy_134 payload; - uint16_t error; -}; -typedef struct anon__lazy_155 nav__4215_59; -typedef struct anon__lazy_174 nav__4215_69; -struct anon__lazy_174 { - uint64_t payload; - uint16_t error; -}; -typedef struct anon__lazy_177 nav__4215_72; -struct anon__lazy_177 { - uint16_t error; - uint8_t payload[8]; -}; -typedef struct anon__lazy_57 nav__4214_39; -typedef struct anon__lazy_180 nav__4214_40; -struct anon__lazy_180 { - struct anon__lazy_57 payload; - uint16_t error; -}; -typedef struct anon__lazy_134 nav__4214_55; -typedef struct anon__lazy_169 nav__4214_57; -typedef struct anon__lazy_184 nav__4213_39; -typedef struct anon__lazy_57 nav__4213_44; -struct anon__lazy_184 { - struct shared_Command__struct_1949__1949 payload; - uint16_t error; -}; -typedef struct anon__lazy_143 nav__4213_57; -typedef struct anon__lazy_180 nav__4213_60; -typedef struct anon__lazy_184 nav__4212_39; -typedef struct anon__lazy_57 nav__4212_44; -typedef struct anon__lazy_192 nav__4220_39; -typedef struct anon__lazy_57 nav__4220_44; -struct anon__lazy_192 { - struct shared_Command__struct_1950__1950 payload; - uint16_t error; -}; -typedef struct anon__lazy_180 nav__4220_57; -typedef struct anon__lazy_192 nav__4219_39; -typedef struct anon__lazy_57 nav__4219_44; -typedef struct anon__lazy_174 nav__4226_38; -typedef struct anon__lazy_155 nav__4226_50; -typedef struct anon__lazy_134 nav__4226_52; -typedef struct anon__lazy_177 nav__4226_64; -typedef struct anon__lazy_174 nav__4225_38; -typedef struct anon__lazy_200 nav__4224_39; -struct anon__lazy_200 { - struct shared_MarkerType__1953 payload; - uint16_t error; -}; -typedef struct anon__lazy_143 nav__4224_54; -typedef struct anon__lazy_174 nav__4224_56; -typedef struct anon__lazy_200 nav__4223_39; -typedef struct anon__lazy_204 nav__4222_39; -struct anon__lazy_204 { - struct shared_Command__struct_1951__1951 payload; - uint16_t error; -}; -typedef struct anon__lazy_143 nav__4222_57; -typedef struct anon__lazy_200 nav__4222_60; -typedef struct anon__lazy_204 nav__4221_39; -typedef struct anon__lazy_209 nav__4171_39; -typedef struct anon__lazy_57 nav__4171_45; -struct anon__lazy_209 { - struct shared_Command__1946 payload; - uint16_t error; -}; -typedef struct anon__lazy_143 nav__4171_66; -typedef struct anon__lazy_184 nav__4171_68; -typedef struct anon__lazy_192 nav__4171_70; -typedef struct anon__lazy_204 nav__4171_72; -typedef struct anon__lazy_174 nav__4171_74; -typedef struct anon__lazy_209 nav__4170_39; -typedef struct anon__lazy_57 nav__4170_45; -typedef struct anon__lazy_209 nav__1085_39; -typedef struct anon__lazy_57 nav__1085_45; -typedef struct anon__lazy_134 nav__1085_71; -typedef struct anon__lazy_155 nav__1085_74; -typedef struct anon__lazy_169 nav__1085_78; -struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 { - struct anon__lazy_134 buffer; - uintptr_t pos; -}; -typedef struct anon__lazy_209 nav__1086_39; -typedef struct anon__lazy_218 nav__1086_42; -typedef struct anon__lazy_57 nav__1086_46; -struct anon__lazy_218 { - uint64_t payload; - bool is_null; -}; -typedef struct anon__lazy_218 nav__1087_40; -typedef struct anon__lazy_57 nav__1087_48; -typedef struct anon__lazy_209 nav__1087_60; -typedef struct anon__lazy_57 nav__760_58; -typedef struct anon__lazy_218 nav__760_71; -typedef struct anon__lazy_229 nav__239_46; -struct anon__lazy_229 { - struct instruments_root_InstrumentHooks__547 *payload; - uint16_t error; -}; -typedef struct anon__lazy_134 nav__239_51; -struct mem_Allocator_VTable__568 { - uint8_t *(*alloc)(void *, uintptr_t, uint8_t, uintptr_t); - bool (*resize)(void *, struct anon__lazy_134, uint8_t, uintptr_t, uintptr_t); - uint8_t *(*remap)(void *, struct anon__lazy_134, uint8_t, uintptr_t, uintptr_t); - void (*free)(void *, struct anon__lazy_134, uint8_t, uintptr_t); -}; -typedef struct anon__lazy_110 nav__239_72; -typedef struct anon__lazy_229 nav__3577_40; -typedef struct anon__lazy_246 nav__3577_51; -struct anon__lazy_246 { - uint8_t *payload; - uint16_t error; -}; -typedef struct anon__lazy_57 nav__1142_39; -struct fs_Dir__1860; -struct fs_Dir__1860 { - int32_t fd; -}; -typedef struct anon__lazy_74 nav__1139_39; -typedef struct anon__lazy_57 nav__1139_41; -typedef struct anon__lazy_57 nav__753_44; -typedef struct anon__lazy_218 nav__753_72; -typedef struct anon__lazy_57 nav__754_45; -typedef struct anon__lazy_134 nav__3888_42; -typedef struct anon__lazy_57 nav__4061_46; -typedef struct anon__lazy_134 nav__3890_41; -typedef struct anon__lazy_57 nav__1233_40; -typedef struct anon__lazy_155 nav__1233_47; -struct os_linux_timespec__struct_2922__2922; -struct os_linux_timespec__struct_2922__2922 { - intptr_t sec; - intptr_t nsec; -}; -typedef struct anon__lazy_283 nav__4075_41; -struct anon__lazy_283 { - struct os_linux_timespec__struct_2922__2922 payload; - uint16_t error; -}; -typedef struct anon__lazy_155 nav__1223_38; -typedef struct anon__lazy_134 nav__1223_41; -typedef struct anon__lazy_134 nav__4103_39; -typedef struct anon__lazy_169 nav__4103_40; -typedef struct anon__lazy_246 nav__4103_51; -typedef struct anon__lazy_134 nav__4104_40; -typedef struct anon__lazy_134 nav__4136_40; -typedef struct anon__lazy_155 nav__4169_38; -typedef struct anon__lazy_134 nav__4169_41; -typedef struct anon__lazy_165 nav__4211_39; -typedef struct anon__lazy_155 nav__4211_44; -typedef struct anon__lazy_134 nav__4211_46; -typedef struct anon__lazy_177 nav__4216_39; -typedef struct anon__lazy_155 nav__4216_44; -typedef struct anon__lazy_134 nav__4216_46; -typedef struct anon__lazy_155 nav__4176_38; -typedef struct anon__lazy_134 nav__4176_41; -typedef struct anon__lazy_57 nav__4217_40; -typedef struct anon__lazy_310 nav__4217_42; -struct anon__lazy_310 { - uintptr_t payload; - bool is_null; -}; -struct cimport_struct_timespec__3100; -struct cimport_struct_timespec__3100 { - long tv_sec; - long tv_nsec; -}; -typedef struct anon__lazy_317 nav__3832_42; -struct anon__lazy_317 { - long payload; - bool is_null; -}; -typedef struct anon__lazy_57 nav__3836_43; -typedef struct anon__lazy_134 nav__4228_52; -typedef struct anon__lazy_246 nav__4229_39; -typedef struct anon__lazy_134 nav__4229_52; -typedef struct anon__lazy_57 nav__4264_39; -typedef struct anon__lazy_57 nav__3783_40; -typedef struct anon__lazy_339 nav__3783_49; -struct anon__lazy_339 { - uint16_t error; - uint8_t payload[4096]; -}; -typedef struct anon__lazy_74 nav__3719_39; -typedef struct anon__lazy_57 nav__3719_42; -typedef struct anon__lazy_339 nav__3719_53; -typedef struct anon__lazy_57 nav__5247_46; -typedef struct anon__lazy_134 nav__3936_39; -typedef struct anon__lazy_155 nav__1232_38; -typedef struct anon__lazy_57 nav__1232_41; -typedef struct anon__lazy_283 nav__1633_39; -typedef struct anon__lazy_155 nav__1222_38; -typedef struct anon__lazy_134 nav__1222_41; -typedef struct anon__lazy_246 nav__5248_39; -typedef struct anon__lazy_155 nav__5248_49; -typedef struct anon__lazy_134 nav__5249_39; -typedef struct anon__lazy_155 nav__4128_38; -typedef struct anon__lazy_134 nav__4128_42; -typedef struct anon__lazy_134 nav__4178_40; -typedef struct anon__lazy_155 nav__4178_43; -typedef struct anon__lazy_155 nav__4177_38; -typedef struct anon__lazy_134 nav__4177_41; -typedef struct anon__lazy_57 nav__5251_39; -typedef struct anon__lazy_310 nav__5251_40; -typedef struct anon__lazy_317 nav__6121_38; -typedef struct anon__lazy_57 nav__6890_40; -typedef struct anon__lazy_134 nav__6890_51; -typedef struct anon__lazy_57 nav__4270_39; -typedef struct anon__lazy_339 nav__1717_39; -typedef struct anon__lazy_57 nav__1717_41; -typedef struct anon__lazy_134 nav__1717_47; -typedef struct anon__lazy_74 nav__3720_39; -typedef struct anon__lazy_374 nav__3720_50; -struct anon__lazy_374 { - int32_t payload; - uint16_t error; -}; -typedef struct anon__lazy_57 nav__6905_45; -typedef struct anon__lazy_57 nav__6907_45; -typedef struct anon__lazy_155 nav__1452_38; -typedef struct anon__lazy_57 nav__1452_40; -typedef struct anon__lazy_155 nav__1444_38; -typedef struct anon__lazy_134 nav__1444_40; -typedef struct anon__lazy_155 nav__6977_38; -typedef struct anon__lazy_398 nav__6977_42; -struct anon__lazy_398 { - uintptr_t f0; - uint8_t f1; -}; -typedef struct anon__lazy_246 nav__6978_39; -typedef struct anon__lazy_134 nav__6978_52; -typedef struct anon__lazy_155 nav__4175_38; -typedef struct anon__lazy_134 nav__4175_41; -typedef struct anon__lazy_57 nav__6980_39; -typedef struct anon__lazy_374 nav__1464_38; -struct io_Writer__3920; -typedef struct anon__lazy_155 nav__7041_48; -typedef struct anon__lazy_57 nav__7041_50; -struct io_Writer__3920 { - void const *context; - struct anon__lazy_155 (*writeFn)(void const *, struct anon__lazy_57); -}; -typedef struct anon__lazy_57 nav__7042_45; -typedef struct anon__lazy_57 nav__7043_45; -typedef struct anon__lazy_155 nav__7045_48; -typedef struct anon__lazy_57 nav__7045_50; -typedef struct anon__lazy_155 nav__4060_38; -typedef struct anon__lazy_57 nav__4060_41; -typedef struct anon__lazy_57 nav__7060_40; -typedef struct anon__lazy_155 nav__7060_43; -typedef struct anon__lazy_57 nav__7069_40; -typedef struct anon__lazy_155 nav__3914_38; -typedef struct anon__lazy_57 nav__3914_42; -typedef struct anon__lazy_155 nav__7059_38; -typedef struct anon__lazy_57 nav__7059_41; -typedef struct anon__lazy_57 nav__7071_40; -typedef struct anon__lazy_155 nav__7071_51; -typedef struct anon__lazy_57 nav__3908_41; -typedef struct anon__lazy_134 nav__3927_43; -typedef struct anon__lazy_155 nav__3927_52; -typedef struct anon__lazy_57 nav__3909_41; -typedef struct anon__lazy_134 nav__3909_47; -typedef struct anon__lazy_155 nav__3852_38; -typedef struct anon__lazy_398 nav__3852_42; -typedef struct anon__lazy_134 nav__3925_43; -typedef struct anon__lazy_134 nav__3926_43; -typedef struct anon__lazy_169 nav__3926_55; -typedef struct anon__lazy_134 nav__7158_39; -typedef struct anon__lazy_155 nav__7158_50; -typedef struct anon__lazy_134 nav__7159_39; -typedef struct anon__lazy_169 nav__7159_40; -typedef struct anon__lazy_246 nav__7159_51; -typedef struct anon__lazy_134 nav__7160_39; -typedef struct anon__lazy_134 nav__240_63; -typedef struct anon__lazy_57 nav__755_58; -typedef struct anon__lazy_218 nav__755_71; -typedef struct anon__lazy_57 nav__756_58; -typedef struct anon__lazy_218 nav__756_71; -typedef struct anon__lazy_57 nav__757_56; -typedef struct anon__lazy_218 nav__757_71; -typedef struct anon__lazy_57 nav__7165_39; -typedef struct anon__lazy_459 nav__7167_45; -struct anon__lazy_459 { - bool array[32]; -}; -typedef struct anon__lazy_461 nav__7167_47; -struct anon__lazy_461 { - bool is_null; - uint8_t payload; -}; -typedef struct anon__lazy_461 nav__7533_38; -typedef struct anon__lazy_459 nav__7533_40; -typedef struct anon__lazy_57 nav__758_56; -typedef struct anon__lazy_218 nav__758_71; -typedef struct anon__lazy_474 nav__246_62; -struct anon__lazy_474 { - uint8_t const *f0; - uint8_t const *f1; -}; -typedef struct anon__lazy_134 nav__246_65; -typedef struct anon__lazy_169 nav__246_67; -typedef struct anon__lazy_134 nav__7541_39; -typedef struct anon__lazy_169 nav__7541_40; -typedef struct anon__lazy_474 nav__7541_43; -typedef struct anon__lazy_134 nav__7542_40; -typedef struct anon__lazy_134 nav__7543_39; -typedef struct anon__lazy_169 nav__7543_40; -typedef struct anon__lazy_474 nav__7543_43; -typedef struct anon__lazy_310 nav__7543_54; -typedef struct anon__lazy_134 nav__7544_39; -typedef struct anon__lazy_474 nav__7586_40; -typedef struct anon__lazy_155 nav__7586_43; -typedef struct anon__lazy_57 nav__7586_44; -struct fmt_FormatOptions__4926; -typedef struct anon__lazy_310 nav__7586_55; -struct fmt_FormatOptions__4926 { - struct anon__lazy_310 precision; - struct anon__lazy_310 width; - uint32_t fill; - uint8_t alignment; -}; -typedef struct anon__lazy_474 nav__7545_39; -struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576; -struct io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29__4568; -struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 { - uint64_t bytes_written; -}; -struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596; -struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *context; -}; -typedef struct anon__lazy_155 nav__7545_53; -typedef struct anon__lazy_57 nav__7545_54; -typedef struct anon__lazy_310 nav__7546_38; -typedef struct anon__lazy_134 nav__7547_39; -typedef struct anon__lazy_169 nav__7547_40; -typedef struct anon__lazy_474 nav__7547_42; -struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984; -struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *context; -}; -typedef struct anon__lazy_155 nav__7547_57; -typedef struct anon__lazy_57 nav__7547_58; -typedef struct anon__lazy_155 nav__7585_38; -typedef struct anon__lazy_57 nav__7585_41; -typedef struct anon__lazy_310 nav__7754_42; -typedef struct anon__lazy_155 nav__7754_46; -typedef struct anon__lazy_57 nav__7754_47; -typedef struct anon__lazy_155 nav__7767_38; -typedef struct anon__lazy_57 nav__7767_41; -typedef struct anon__lazy_134 nav__4134_39; -typedef struct anon__lazy_155 nav__7570_38; -typedef struct anon__lazy_57 nav__7570_42; -typedef struct anon__lazy_517 nav__7598_38; -struct anon__lazy_517 { - uint16_t error; - uint8_t payload; -}; -typedef struct anon__lazy_155 nav__7614_38; -typedef struct anon__lazy_57 nav__7614_40; -typedef struct anon__lazy_517 nav__7614_48; -typedef struct anon__lazy_143 nav__7614_50; -typedef struct anon__lazy_57 nav__7768_39; -typedef struct anon__lazy_310 nav__7768_44; -typedef struct anon__lazy_155 nav__7768_48; -typedef struct anon__lazy_134 nav__7768_57; -typedef struct anon__lazy_517 nav__7768_60; -typedef struct anon__lazy_155 nav__4129_38; -typedef struct anon__lazy_57 nav__4129_42; -typedef struct anon__lazy_134 nav__4129_50; -typedef struct anon__lazy_155 nav__4038_38; -typedef struct anon__lazy_57 nav__4038_40; -typedef struct anon__lazy_143 nav__7604_38; -typedef struct anon__lazy_57 nav__7604_40; -typedef struct anon__lazy_532 nav__7604_48; -struct anon__lazy_532 { - uint8_t array[2]; -}; -typedef struct anon__lazy_534 nav__7604_52; -struct anon__lazy_534 { - uint8_t array[3]; -}; -typedef struct anon__lazy_536 nav__7604_56; -struct anon__lazy_536 { - uint8_t array[4]; -}; -typedef struct anon__lazy_517 nav__7597_38; -typedef struct anon__lazy_517 nav__7769_38; -typedef struct anon__lazy_134 nav__7769_40; -typedef struct anon__lazy_517 nav__7599_38; -typedef struct anon__lazy_134 nav__7599_40; -typedef struct anon__lazy_57 nav__7064_40; -typedef struct anon__lazy_155 nav__7064_43; -typedef struct anon__lazy_143 nav__7606_38; -typedef struct anon__lazy_532 nav__7606_40; -typedef struct anon__lazy_143 nav__7608_38; -typedef struct anon__lazy_534 nav__7608_40; -typedef struct anon__lazy_143 nav__7612_38; -typedef struct anon__lazy_536 nav__7612_40; -typedef struct anon__lazy_143 nav__7610_38; -typedef struct anon__lazy_534 nav__7610_40; -typedef struct anon__lazy_57 nav__759_64; -typedef struct anon__lazy_218 nav__759_72; -typedef struct anon__lazy_283 nav__3834_41; -struct Target_Os__625; -union Target_Os_VersionRange__681; -struct SemanticVersion_Range__686; -struct SemanticVersion__684; -typedef struct anon__lazy_57 nav__265_43; -struct SemanticVersion__684 { - uintptr_t major; - uintptr_t minor; - uintptr_t patch; - struct anon__lazy_57 pre; - struct anon__lazy_57 build; -}; -struct SemanticVersion_Range__686 { - struct SemanticVersion__684 zig_e_min; - struct SemanticVersion__684 zig_e_max; -}; -struct Target_Os_HurdVersionRange__688; -struct Target_Os_HurdVersionRange__688 { - struct SemanticVersion_Range__686 range; - struct SemanticVersion__684 glibc; -}; -struct Target_Os_LinuxVersionRange__690; -struct Target_Os_LinuxVersionRange__690 { - struct SemanticVersion_Range__686 range; - struct SemanticVersion__684 glibc; - uint32_t android; -}; -struct Target_Os_WindowsVersion_Range__746; -struct Target_Os_WindowsVersion_Range__746 { - uint32_t zig_e_min; - uint32_t zig_e_max; -}; -union Target_Os_VersionRange__681 { - struct SemanticVersion_Range__686 semver; - struct Target_Os_HurdVersionRange__688 hurd; - struct Target_Os_LinuxVersionRange__690 linux; - struct Target_Os_WindowsVersion_Range__746 windows; -}; -struct Target_Os__625 { - union Target_Os_VersionRange__681 version_range; - uint8_t tag; -}; -struct Target_DynamicLinker__800; -struct Target_DynamicLinker__800 { - uint8_t buffer[255]; - uint8_t len; -}; -typedef struct anon__lazy_134 nav__3574_40; -typedef struct anon__lazy_134 nav__3575_40; -typedef struct anon__lazy_134 nav__3576_40; -typedef struct anon__lazy_134 nav__3538_46; -typedef struct anon__lazy_134 nav__236_46; -struct Target_Cpu_Feature_Set__817; -struct Target_Cpu_Feature_Set__817 { - uintptr_t ints[5]; -}; -struct Target_Cpu__785; -struct Target_Cpu_Model__812; -struct Target_Cpu__785 { - struct Target_Cpu_Model__812 const *model; - struct Target_Cpu_Feature_Set__817 features; - uint8_t arch; -}; -typedef struct anon__lazy_57 nav__264_46; -struct Target_Cpu_Model__812 { - struct anon__lazy_57 name; - struct anon__lazy_57 llvm_name; - struct Target_Cpu_Feature_Set__817 features; -}; -struct Target__623; -typedef struct anon__lazy_57 nav__266_51; -struct Target__623 { - struct Target_Cpu__785 cpu; - struct Target_Os__625 os; - uint8_t abi; - uint8_t ofmt; - struct Target_DynamicLinker__800 dynamic_linker; -}; -struct builtin_CallingConvention__266; -struct builtin_CallingConvention_CommonOptions__268; -typedef struct anon__lazy_218 nav__465_40; -struct builtin_CallingConvention_CommonOptions__268 { - struct anon__lazy_218 incoming_stack_alignment; -}; -struct builtin_CallingConvention_X86RegparmOptions__270; -struct builtin_CallingConvention_X86RegparmOptions__270 { - struct anon__lazy_218 incoming_stack_alignment; - uint8_t register_params; -}; -struct builtin_CallingConvention_ArmInterruptOptions__272; -struct builtin_CallingConvention_ArmInterruptOptions__272 { - struct anon__lazy_218 incoming_stack_alignment; - uint8_t type; -}; -struct builtin_CallingConvention_MipsInterruptOptions__274; -struct builtin_CallingConvention_MipsInterruptOptions__274 { - struct anon__lazy_218 incoming_stack_alignment; - uint8_t mode; -}; -struct builtin_CallingConvention_RiscvInterruptOptions__276; -struct builtin_CallingConvention_RiscvInterruptOptions__276 { - struct anon__lazy_218 incoming_stack_alignment; - uint8_t mode; -}; -struct builtin_CallingConvention__266 { - union { - struct builtin_CallingConvention_CommonOptions__268 x86_64_sysv; - struct builtin_CallingConvention_CommonOptions__268 x86_64_win; - struct builtin_CallingConvention_CommonOptions__268 x86_64_regcall_v3_sysv; - struct builtin_CallingConvention_CommonOptions__268 x86_64_regcall_v4_win; - struct builtin_CallingConvention_CommonOptions__268 x86_64_vectorcall; - struct builtin_CallingConvention_CommonOptions__268 x86_64_interrupt; - struct builtin_CallingConvention_X86RegparmOptions__270 x86_sysv; - struct builtin_CallingConvention_X86RegparmOptions__270 x86_win; - struct builtin_CallingConvention_X86RegparmOptions__270 x86_stdcall; - struct builtin_CallingConvention_CommonOptions__268 x86_fastcall; - struct builtin_CallingConvention_CommonOptions__268 x86_thiscall; - struct builtin_CallingConvention_CommonOptions__268 x86_thiscall_mingw; - struct builtin_CallingConvention_CommonOptions__268 x86_regcall_v3; - struct builtin_CallingConvention_CommonOptions__268 x86_regcall_v4_win; - struct builtin_CallingConvention_CommonOptions__268 x86_vectorcall; - struct builtin_CallingConvention_CommonOptions__268 x86_interrupt; - struct builtin_CallingConvention_CommonOptions__268 aarch64_aapcs; - struct builtin_CallingConvention_CommonOptions__268 aarch64_aapcs_darwin; - struct builtin_CallingConvention_CommonOptions__268 aarch64_aapcs_win; - struct builtin_CallingConvention_CommonOptions__268 aarch64_vfabi; - struct builtin_CallingConvention_CommonOptions__268 aarch64_vfabi_sve; - struct builtin_CallingConvention_CommonOptions__268 arm_aapcs; - struct builtin_CallingConvention_CommonOptions__268 arm_aapcs_vfp; - struct builtin_CallingConvention_ArmInterruptOptions__272 arm_interrupt; - struct builtin_CallingConvention_CommonOptions__268 mips64_n64; - struct builtin_CallingConvention_CommonOptions__268 mips64_n32; - struct builtin_CallingConvention_MipsInterruptOptions__274 mips64_interrupt; - struct builtin_CallingConvention_CommonOptions__268 mips_o32; - struct builtin_CallingConvention_MipsInterruptOptions__274 mips_interrupt; - struct builtin_CallingConvention_CommonOptions__268 riscv64_lp64; - struct builtin_CallingConvention_CommonOptions__268 riscv64_lp64_v; - struct builtin_CallingConvention_RiscvInterruptOptions__276 riscv64_interrupt; - struct builtin_CallingConvention_CommonOptions__268 riscv32_ilp32; - struct builtin_CallingConvention_CommonOptions__268 riscv32_ilp32_v; - struct builtin_CallingConvention_RiscvInterruptOptions__276 riscv32_interrupt; - struct builtin_CallingConvention_CommonOptions__268 sparc64_sysv; - struct builtin_CallingConvention_CommonOptions__268 sparc_sysv; - struct builtin_CallingConvention_CommonOptions__268 powerpc64_elf; - struct builtin_CallingConvention_CommonOptions__268 powerpc64_elf_altivec; - struct builtin_CallingConvention_CommonOptions__268 powerpc64_elf_v2; - struct builtin_CallingConvention_CommonOptions__268 powerpc_sysv; - struct builtin_CallingConvention_CommonOptions__268 powerpc_sysv_altivec; - struct builtin_CallingConvention_CommonOptions__268 powerpc_aix; - struct builtin_CallingConvention_CommonOptions__268 powerpc_aix_altivec; - struct builtin_CallingConvention_CommonOptions__268 wasm_mvp; - struct builtin_CallingConvention_CommonOptions__268 arc_sysv; - struct builtin_CallingConvention_CommonOptions__268 bpf_std; - struct builtin_CallingConvention_CommonOptions__268 csky_sysv; - struct builtin_CallingConvention_CommonOptions__268 csky_interrupt; - struct builtin_CallingConvention_CommonOptions__268 hexagon_sysv; - struct builtin_CallingConvention_CommonOptions__268 hexagon_sysv_hvx; - struct builtin_CallingConvention_CommonOptions__268 lanai_sysv; - struct builtin_CallingConvention_CommonOptions__268 loongarch64_lp64; - struct builtin_CallingConvention_CommonOptions__268 loongarch32_ilp32; - struct builtin_CallingConvention_CommonOptions__268 m68k_sysv; - struct builtin_CallingConvention_CommonOptions__268 m68k_gnu; - struct builtin_CallingConvention_CommonOptions__268 m68k_rtd; - struct builtin_CallingConvention_CommonOptions__268 m68k_interrupt; - struct builtin_CallingConvention_CommonOptions__268 msp430_eabi; - struct builtin_CallingConvention_CommonOptions__268 propeller_sysv; - struct builtin_CallingConvention_CommonOptions__268 s390x_sysv; - struct builtin_CallingConvention_CommonOptions__268 s390x_sysv_vx; - struct builtin_CallingConvention_CommonOptions__268 ve_sysv; - struct builtin_CallingConvention_CommonOptions__268 xcore_xs1; - struct builtin_CallingConvention_CommonOptions__268 xcore_xs2; - struct builtin_CallingConvention_CommonOptions__268 xtensa_call0; - struct builtin_CallingConvention_CommonOptions__268 xtensa_windowed; - struct builtin_CallingConvention_CommonOptions__268 amdgcn_device; - struct builtin_CallingConvention_CommonOptions__268 amdgcn_cs; - } payload; - uint8_t tag; -}; -struct std_Options__4269; -typedef struct anon__lazy_310 nav__97_39; -struct std_Options__4269 { - struct anon__lazy_310 page_size_min; - struct anon__lazy_310 page_size_max; - uintptr_t fmt_max_depth; - bool enable_segfault_handler; - uint8_t log_level; - bool crypto_always_getrandom; - bool crypto_fork_safety; - bool keep_sigpipe; - bool http_disable_tls; - bool http_enable_ssl_key_log_file; - uint8_t side_channels_mitigations; -}; -typedef struct anon__lazy_310 nav__3554_38; -typedef struct anon__lazy_134 nav__3565_43; -typedef struct anon__lazy_57 nav__3597_40; -static uint8_t const __anon_1845[21]; -static uint8_t const __anon_1916[21]; -static uint8_t const __anon_2757[70]; -static uint8_t const __anon_2761[83]; -static uint8_t const __anon_3003[89]; -static uint8_t const __anon_4667[10]; -static uint8_t const __anon_4948[1]; -static uint8_t const __anon_4968[1]; -static uint8_t const __anon_5138[3]; -static uint8_t const __anon_5013[4]; -static uint8_t const __anon_5291[10]; -#define c_instrument_hooks_set_feature__238 instrument_hooks_set_feature -zig_extern void instrument_hooks_set_feature(uint64_t, bool); -static void features_set_feature__325(uint64_t, bool); -static void bit_set_IntegerBitSet_2864_29_set__364(uint64_t *, uintptr_t); -static void bit_set_IntegerBitSet_2864_29_unset__366(uint64_t *, uintptr_t); -static void debug_assert__180(bool); -static uint64_t bit_set_IntegerBitSet_2864_29_maskBit__385(uintptr_t); -static nav__1074_39 fifo_UnixPipe_openPipe__1074(nav__1074_41); -static nav__1076_39 fifo_UnixPipe_openWrite__1076(struct mem_Allocator__565, nav__1076_42); -static nav__1075_39 fifo_UnixPipe_openRead__1075(struct mem_Allocator__565, nav__1075_42); -static nav__751_39 instruments_perf_PerfInstrument_init__751(struct mem_Allocator__565); -static nav__726_39 instruments_root_InstrumentHooks_init__726(struct mem_Allocator__565); -static uint16_t fifo_UnixPipe_Writer_sendCmd__1080(struct fifo_UnixPipe_Writer__600 *, struct shared_Command__1946); -static nav__4173_38 bincode_deserializeInt__anon_2322__4173(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201); -static nav__4172_38 bincode_deserializeAlloc__anon_2311__4172(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4215_40 bincode_deserializePointerAlloc__anon_2448__4215(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4214_40 bincode_deserializeAlloc__anon_2435__4214(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4213_39 bincode_deserializeStructAlloc__anon_2410__4213(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4212_39 bincode_deserializeAlloc__anon_2381__4212(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static uint16_t bincode_deserializeAlloc__anon_2500__4218(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4220_39 bincode_deserializeStructAlloc__anon_2564__4220(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4219_39 bincode_deserializeAlloc__anon_2545__4219(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4226_38 bincode_deserializeInt__anon_2687__4226(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201); -static nav__4225_38 bincode_deserializeAlloc__anon_2682__4225(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4224_39 bincode_deserializeUnionAlloc__anon_2669__4224(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4223_39 bincode_deserializeAlloc__anon_2635__4223(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4222_39 bincode_deserializeStructAlloc__anon_2617__4222(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4221_39 bincode_deserializeAlloc__anon_2603__4221(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4171_39 bincode_deserializeUnionAlloc__anon_2306__4171(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__4170_39 bincode_deserializeAlloc__anon_2209__4170(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201, struct mem_Allocator__565); -static nav__1085_39 fifo_UnixPipe_Reader_recvCmd__1085(struct fifo_UnixPipe_Reader__602 *); -static nav__1086_39 fifo_UnixPipe_Reader_waitForResponse__1086(struct fifo_UnixPipe_Reader__602 *, nav__1086_42); -static uint16_t fifo_UnixPipe_Reader_waitForAck__1087(struct fifo_UnixPipe_Reader__602 *, nav__1087_40); -static uint16_t instruments_perf_PerfInstrument_send_version__760(struct instruments_perf_PerfInstrument__559 *, uint64_t); -#define c_instrument_hooks_init__239 instrument_hooks_init -zig_extern struct instruments_root_InstrumentHooks__547 *instrument_hooks_init(void); -static nav__3577_40 mem_Allocator_create__anon_858__3577(struct mem_Allocator__565); -static struct instruments_valgrind_ValgrindInstrument__554 instruments_valgrind_ValgrindInstrument_init__739(struct mem_Allocator__565); -static uint16_t fs_accessAbsolute__1142(nav__1142_39, struct fs_File_OpenFlags__1858); -static nav__1139_39 fs_openFileAbsolute__1139(nav__1139_41, struct fs_File_OpenFlags__1858); -static void utils_setNonBlocking__3833(int32_t); -static struct fifo_UnixPipe_Writer__600 fifo_UnixPipe_Writer_init__1077(struct fs_File__608, struct mem_Allocator__565); -static struct fifo_UnixPipe_Reader__602 fifo_UnixPipe_Reader_init__1082(struct fs_File__608, struct mem_Allocator__565); -static uint16_t instruments_perf_PerfInstrument_send_cmd__753(struct instruments_perf_PerfInstrument__559 *, struct shared_Command__1946); -static bool instruments_perf_PerfInstrument_is_instrumented__754(struct instruments_perf_PerfInstrument__559 *); -static struct array_list_ArrayListAligned_28u8_2cnull_29__1974 array_list_ArrayListAligned_28u8_2cnull_29_init__3888(struct mem_Allocator__565); -static struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 array_list_ArrayListAligned_28u8_2cnull_29_writer__3913(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *); -static uint16_t bincode_serialize__anon_2015__4061(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__1946); -static void array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(struct array_list_ArrayListAligned_28u8_2cnull_29__1974); -static uint8_t const (*mem_asBytes__anon_2057__4062(uint32_t const *))[4]; -static uint16_t fs_File_writeAll__1233(struct fs_File__608, nav__1233_40); -static zig_i128 time_nanoTimestamp__4075(void); -static nav__1223_38 fs_File_readAll__1223(struct fs_File__608, nav__1223_41); -static nav__4103_40 mem_Allocator_alloc__anon_2153__4103(struct mem_Allocator__565, uintptr_t); -static void mem_Allocator_free__anon_2159__4104(struct mem_Allocator__565, nav__4104_40); -static struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 io_fixed_buffer_stream_fixedBufferStream__anon_2181__4136(nav__4136_40); -static struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_reader__4125(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *); -static nav__4169_38 io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169(void const *, nav__4169_41); -static nav__4211_39 io_Reader_readBytesNoEof__anon_2368__4211(struct io_Reader__2337); -static nav__4216_39 io_Reader_readBytesNoEof__anon_2461__4216(struct io_Reader__2337); -static nav__4176_38 io_Reader_readAll__4176(struct io_Reader__2337, nav__4176_41); -static zig_cold zig_noreturn void bincode_invalidProtocol__anon_2485__4217(void); -static void utils_sleep__3832(uint64_t); -static void shared_Command_deinit__3836(struct shared_Command__1946, struct mem_Allocator__565); -static void instruments_perf_PerfInstrument_deinit__752(struct instruments_perf_PerfInstrument__559 *); -static void mem_Allocator_destroy__anon_2777__4228(struct mem_Allocator__565, struct instruments_root_InstrumentHooks__547 *); -static zig_noreturn void posix_exit__1442(uint8_t); -static nav__4229_39 mem_Allocator_allocBytesWithAlignment__anon_2793__4229(struct mem_Allocator__565, uintptr_t, uintptr_t); -static bool fs_path_isAbsolute__4264(nav__4264_39); -static struct fs_Dir__1860 fs_cwd__1134(void); -static uint16_t fs_Dir_access__3783(struct fs_Dir__1860, nav__3783_40, struct fs_File_OpenFlags__1858); -static nav__3719_39 fs_Dir_openFile__3719(struct fs_Dir__1860, nav__3719_42, struct fs_File_OpenFlags__1858); -static uint16_t bincode_serializeUnion__anon_2860__5247(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__1946); -static nav__3936_39 array_list_ArrayListAligned_28u8_2cnull_29_allocatedSlice__3936(struct array_list_ArrayListAligned_28u8_2cnull_29__1974); -static nav__1232_38 fs_File_write__1232(struct fs_File__608, nav__1232_41); -static nav__1633_39 posix_clock_gettime__1633(uint32_t); -static nav__1222_38 fs_File_read__1222(struct fs_File__608, nav__1222_41); -static nav__5248_39 mem_Allocator_allocWithSizeAndAlignment__anon_2953__5248(struct mem_Allocator__565, uintptr_t, uintptr_t); -static nav__5249_39 mem_sliceAsBytes__anon_2966__5249(nav__5249_39); -static uint8_t mem_Alignment_fromByteUnits__1046(uintptr_t); -static nav__4128_38 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_read__4128(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *, nav__4128_42); -static uint16_t io_Reader_readNoEof__4178(struct io_Reader__2337, nav__4178_40); -static nav__4177_38 io_Reader_readAtLeast__4177(struct io_Reader__2337, nav__4177_41, uintptr_t); -static zig_cold zig_noreturn void debug_no_panic_call__5251(nav__5251_39, nav__5251_40); -static nav__6121_38 math_cast__anon_3113__6121(uint64_t); -static void mem_Allocator_free__anon_3185__6890(struct mem_Allocator__565, nav__6890_40); -static void fifo_UnixPipe_Writer_deinit__1081(struct fifo_UnixPipe_Writer__600 *); -static void fifo_UnixPipe_Reader_deinit__1088(struct fifo_UnixPipe_Reader__602 *); -static bool fs_path_isAbsolutePosix__4270(nav__4270_39); -static nav__1717_39 posix_toPosixPath__1717(nav__1717_41); -static uint16_t fs_Dir_accessZ__3784(struct fs_Dir__1860, uint8_t const *, struct fs_File_OpenFlags__1858); -static nav__3720_39 fs_Dir_openFileZ__3720(struct fs_Dir__1860, uint8_t const *, struct fs_File_OpenFlags__1858); -static uint16_t bincode_serialize__anon_3275__6904(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, uint32_t); -static uint16_t bincode_serialize__anon_3277__6905(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1949__1949); -static uint16_t bincode_serialize__anon_3279__6906(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005); -static uint16_t bincode_serialize__anon_3281__6907(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1950__1950); -static uint16_t bincode_serialize__anon_3283__6908(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1951__1951); -static uint16_t bincode_serialize__anon_3285__6909(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, uint64_t); -static nav__1452_38 posix_write__1452(int32_t, nav__1452_40); -static uint16_t posix_errno__anon_3451__6976(int); -static uint16_t posix_unexpectedErrno__1716(uint16_t); -static nav__1444_38 posix_read__1444(int32_t, nav__1444_40); -static nav__6977_38 math_mul__anon_3472__6977(uintptr_t, uintptr_t); -static nav__6978_39 mem_Allocator_allocBytesWithAlignment__anon_3474__6978(struct mem_Allocator__565, uintptr_t, uintptr_t); -static bool math_isPowerOfTwo__anon_3486__6979(uintptr_t); -static nav__4175_38 io_Reader_read__4175(struct io_Reader__2337, nav__4175_41); -static nav__6980_39 mem_sliceAsBytes__anon_3508__6980(nav__6980_39); -static void fs_File_close__1179(struct fs_File__608); -static uint16_t posix_faccessatZ__1608(int32_t, uint8_t const *, uint32_t, uint32_t); -static nav__1464_38 posix_openatZ__1464(int32_t, uint8_t const *, uint32_t, uintptr_t); -static uint16_t posix_flock__1625(int32_t, int32_t); -static void posix_close__1422(int32_t); -static uint16_t bincode_serializeInt__anon_3646__7041(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, uint32_t); -static uint16_t bincode_serializeStruct__anon_3651__7042(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1949__1949); -static uint16_t bincode_serializeStruct__anon_3652__7043(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1950__1950); -static uint16_t bincode_serializeStruct__anon_3653__7044(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_Command__struct_1951__1951); -static uint16_t bincode_serializeInt__anon_3654__7045(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, uint64_t); -static uint16_t posix_errno__anon_3665__7047(intptr_t); -static nav__4060_38 io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060(void const *, nav__4060_41); -static uint16_t io_Writer_writeAll__7060(struct io_Writer__3920, nav__7060_40); -static uint16_t bincode_serialize__anon_3956__7069(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, nav__7069_40); -static uint16_t bincode_serialize__anon_3958__7070(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_MarkerType__1953); -static nav__3914_38 array_list_ArrayListAligned_28u8_2cnull_29_appendWrite__3914(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, nav__3914_42); -static nav__7059_38 io_Writer_write__7059(struct io_Writer__3920, nav__7059_41); -static uint16_t bincode_serializePointer__anon_3971__7071(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, nav__7071_40); -static uint16_t bincode_serializeUnion__anon_3972__7072(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005, struct shared_MarkerType__1953); -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_appendSlice__3908(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, nav__3908_41); -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureUnusedCapacity__3927(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, uintptr_t); -static void array_list_ArrayListAligned_28u8_2cnull_29_appendSliceAssumeCapacity__3909(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, nav__3909_41); -static nav__3852_38 array_list_addOrOom__3852(uintptr_t, uintptr_t); -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacity__3925(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, uintptr_t); -static uintptr_t array_list_ArrayListAlignedUnmanaged_28u8_2cnull_29_growCapacity__7131(uintptr_t, uintptr_t); -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacityPrecise__3926(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *, uintptr_t); -static nav__7158_39 mem_Allocator_remap__anon_4029__7158(struct mem_Allocator__565, nav__7158_39, uintptr_t); -static nav__7159_40 mem_Allocator_alignedAlloc__anon_4034__7159(struct mem_Allocator__565, uintptr_t); -static nav__7160_39 mem_bytesAsSlice__anon_4049__7160(nav__7160_39); -#define c_instrument_hooks_deinit__240 instrument_hooks_deinit -zig_extern void instrument_hooks_deinit(struct instruments_root_InstrumentHooks__547 *); -#define c_instrument_hooks_is_instrumented__241 instrument_hooks_is_instrumented -zig_extern bool instrument_hooks_is_instrumented(struct instruments_root_InstrumentHooks__547 *); -static zig_cold uint16_t instruments_perf_PerfInstrument_start_benchmark__755(struct instruments_perf_PerfInstrument__559 *); -#define c_instrument_hooks_start_benchmark__242 instrument_hooks_start_benchmark -zig_extern uint8_t instrument_hooks_start_benchmark(struct instruments_root_InstrumentHooks__547 *); -static bool features_is_feature_enabled__326(uint64_t); -static bool bit_set_IntegerBitSet_2864_29_isSet__361(uint64_t, uintptr_t); -static zig_cold uint16_t instruments_perf_PerfInstrument_stop_benchmark__756(struct instruments_perf_PerfInstrument__559 *); -#define c_instrument_hooks_stop_benchmark__243 instrument_hooks_stop_benchmark -zig_extern uint8_t instrument_hooks_stop_benchmark(struct instruments_root_InstrumentHooks__547 *); -static uint16_t instruments_perf_PerfInstrument_set_executed_benchmark__757(struct instruments_perf_PerfInstrument__559 *, uint32_t, uint8_t const *); -#define c_instrument_hooks_set_executed_benchmark__244 instrument_hooks_set_executed_benchmark -zig_extern uint8_t instrument_hooks_set_executed_benchmark(struct instruments_root_InstrumentHooks__547 *, uint32_t, uint8_t const *); -static nav__7165_39 mem_span__anon_4156__7165(uint8_t const *); -static uintptr_t mem_len__anon_4165__7166(uint8_t const *); -static uintptr_t mem_indexOfSentinel__anon_4173__7167(uint8_t const *); -static bool math_isPowerOfTwo__anon_4184__7168(void); -static nav__7533_38 simd_firstTrue__anon_4396__7533(nav__7533_40); -static uintptr_t mem_alignForward__anon_4399__7534(uintptr_t, uintptr_t); -static bool mem_isAligned__915(uintptr_t, uintptr_t); -static bool mem_isValidAlignGeneric__anon_4457__7535(uintptr_t); -static uintptr_t mem_alignBackward__anon_4458__7536(uintptr_t, uintptr_t); -static bool mem_isAlignedGeneric__anon_4464__7537(uint64_t, uint64_t); -static uint64_t mem_alignBackward__anon_4466__7538(uint64_t, uint64_t); -static bool mem_isValidAlignGeneric__anon_4468__7539(uint64_t); -static bool math_isPowerOfTwo__anon_4469__7540(uint64_t); -#define c_instrument_hooks_executed_benchmark__245 instrument_hooks_executed_benchmark -zig_extern uint8_t instrument_hooks_executed_benchmark(struct instruments_root_InstrumentHooks__547 *, uint32_t, uint8_t const *); -static uint16_t instruments_perf_PerfInstrument_set_integration__758(struct instruments_perf_PerfInstrument__559 *, uint8_t const *, uint8_t const *); -#define c_instrument_hooks_set_integration__246 instrument_hooks_set_integration -zig_extern uint8_t instrument_hooks_set_integration(struct instruments_root_InstrumentHooks__547 *, uint8_t const *, uint8_t const *); -static nav__7541_40 fmt_allocPrintZ__anon_4506__7541(struct mem_Allocator__565, nav__7541_43); -static void mem_Allocator_free__anon_4508__7542(struct mem_Allocator__565, nav__7542_40); -static nav__7543_40 fmt_allocPrint__anon_4533__7543(struct mem_Allocator__565, nav__7543_43); -static nav__7544_39 mem_sliceAsBytes__anon_4540__7544(nav__7544_39); -static uint16_t fmt_format__anon_4615__7586(struct io_Writer__3920, nav__7586_40); -static uint64_t fmt_count__anon_4547__7545(nav__7545_39); -static nav__7546_38 math_cast__anon_4549__7546(uint64_t); -static nav__7547_40 fmt_bufPrint__anon_4558__7547(nav__7547_39, nav__7547_42); -static struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 io_counting_writer_countingWriter__anon_4579__7572(void); -static struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_writer__7571(struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *); -static nav__7585_38 io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWr__7585(void const *, nav__7585_41); -static uint16_t fmt_formatType__anon_4940__7754(uint8_t const *, struct fmt_FormatOptions__4926, struct io_Writer__3920, uintptr_t); -static struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_writer__4126(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *); -static nav__7767_38 io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write__7767(void const *, nav__7767_41); -static nav__4134_39 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_getWritten__4134(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178); -static nav__7570_38 io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_write__7570(struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *, nav__7570_42); -static nav__7598_38 unicode_utf8ByteSequenceLength__7598(uint8_t); -static nav__7614_38 unicode_utf8CountCodepoints__7614(nav__7614_40); -static uint16_t fmt_formatBuf__anon_5040__7768(nav__7768_39, struct fmt_FormatOptions__4926, struct io_Writer__3920); -static nav__4129_38 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_write__4129(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *, nav__4129_42); -static nav__4038_38 io_dummyWrite__4038(nav__4038_40); -static nav__7604_38 unicode_utf8Decode__7604(nav__7604_40); -static nav__7597_38 unicode_utf8CodepointSequenceLength__7597(uint32_t); -static nav__7769_38 unicode_utf8EncodeImpl__anon_5170__7769(uint32_t, nav__7769_40); -static nav__7599_38 unicode_utf8Encode__7599(uint32_t, nav__7599_40); -static uint16_t io_Writer_writeBytesNTimes__7064(struct io_Writer__3920, nav__7064_40, uintptr_t); -static nav__7606_38 unicode_utf8Decode2__7606(nav__7606_40); -static nav__7608_38 unicode_utf8Decode3__7608(nav__7608_40); -static nav__7612_38 unicode_utf8Decode4__7612(nav__7612_40); -static bool unicode_isSurrogateCodepoint__7677(uint32_t); -static nav__7610_38 unicode_utf8Decode3AllowSurrogateHalf__7610(nav__7610_40); -static uint16_t instruments_perf_PerfInstrument_add_marker__759(struct instruments_perf_PerfInstrument__559 *, uint32_t, struct shared_MarkerType__1953); -#define c_instrument_hooks_add_marker__251 instrument_hooks_add_marker -zig_extern uint8_t instrument_hooks_add_marker(struct instruments_root_InstrumentHooks__547 *, uint32_t, uint8_t, uint64_t); -#define c_instrument_hooks_current_timestamp__252 instrument_hooks_current_timestamp -zig_extern uint64_t instrument_hooks_current_timestamp(void); -static uint64_t utils_clock_gettime_monotonic__3834(void); -static uint64_t const builtin_zig_backend__257; -static bool const start_simplified_logic__109; -static uint8_t const builtin_output_mode__258; -static uint8_t const builtin_link_mode__259; -static uint64_t features_features__324; -static uintptr_t const bit_set_IntegerBitSet_2864_29_bit_length__355; -static bool const builtin_link_libc__269; -static bool const posix_use_libc__1285; -static struct Target_Os__625 const builtin_os__265; -static uint8_t const c_native_os__1727; -static struct Target_DynamicLinker__800 const Target_DynamicLinker_none__3449; -static bool const builtin_is_test__261; -static uint8_t *heap_CAllocator_alloc__3573(void *, uintptr_t, uint8_t, uintptr_t); -static bool heap_CAllocator_resize__3574(void *, nav__3574_40, uint8_t, uintptr_t, uintptr_t); -static uint8_t *heap_CAllocator_remap__3575(void *, nav__3575_40, uint8_t, uintptr_t, uintptr_t); -static void heap_CAllocator_free__3576(void *, nav__3576_40, uint8_t, uintptr_t); -static uint8_t *heap_CAllocator_alignedAlloc__3570(uintptr_t, uint8_t); -static uintptr_t heap_CAllocator_alignedAllocSize__3572(uint8_t *); -static void heap_CAllocator_alignedFree__3571(uint8_t *); -static uintptr_t mem_Alignment_toByteUnits__1045(uint8_t); -static struct mem_Allocator__565 const heap_c_allocator__3538; -static struct mem_Allocator__565 const c_allocator__236; -static struct Target_Cpu_Feature_Set__817 const Target_Cpu_Feature_Set_empty__3494; -static struct Target_Cpu__785 const builtin_cpu__264; -static uint8_t const builtin_abi__263; -static uint8_t const builtin_object_format__267; -static struct Target__623 const builtin_target__266; -static struct builtin_CallingConvention__266 const builtin_CallingConvention_c__465; -zig_extern uint8_t running_on_valgrind(void); -static uint8_t const (*const shared_RUNNER_CTL_FIFO__3701)[21]; -static uint8_t const (*const shared_RUNNER_ACK_FIFO__3702)[21]; -static uint64_t const c_PROTOCOL_VERSION__237; -static uint8_t const mem_native_endian__769; -zig_extern int printf(char const *, ...); -zig_extern int fcntl(int, int, ...); -static int const cimport_F_GETFL__5129; -static int const cimport_O_NONBLOCK__5105; -static int const cimport_F_SETFL__5130; -static uint8_t const os_linux_native_arch__2633; -zig_extern int nanosleep(struct cimport_struct_timespec__3100 const *, struct cimport_struct_timespec__3100 *); -static int const cimport_EINTR__6758; -zig_extern zig_noreturn void exit(int); -static uint8_t const fs_path_native_os__4243; -static uint8_t const fs_native_os__1097; -static uint8_t const fs_Dir_native_os__3825; -static bool const fs_File_is_windows__1273; -static uint8_t const posix_native_os__1283; -zig_extern int clock_gettime(uint32_t, struct os_linux_timespec__struct_2922__2922 *); -static uint8_t const builtin_mode__268; -static bool const debug_runtime_safety__159; -zig_extern int flock(int32_t, int); -static bool const fs_Dir_have_flock__3826; -zig_extern intptr_t write(int32_t, uint8_t const *, uintptr_t); -static uint8_t const c_native_abi__1725; -zig_extern int *zig_e___errno_location(void) zig_mangled(zig_e___errno_location, "__errno_location"); -static bool const posix_unexpected_error_tracing__1714; -zig_extern intptr_t read(int32_t, uint8_t *, uintptr_t); -zig_extern int faccessat(int32_t, uint8_t const *, unsigned int, unsigned int); -static bool const posix_lfs64_abi__1713; -zig_extern int openat64(int, uint8_t const *, uint32_t, ...); -zig_extern int close(int32_t); -zig_extern void callgrind_zero_stats(void); -zig_extern void callgrind_start_instrumentation(void); -zig_extern void callgrind_stop_instrumentation(void); -zig_extern void callgrind_dump_stats_at(uint8_t const *); -static bool const mem_backend_supports_vectors__797; -static bool const builtin_valgrind_support__272; -static bool const debug_default_enable_segfault_handler__205; -static uint8_t const log_default_level__7302; -static struct std_Options__4269 const std_options__97; -static nav__3554_38 const heap_page_size_min_default__3554; -static uintptr_t const heap_page_size_min__3533; -static uint16_t const fmt_max_format_args__7370; -static uint8_t const (*const fmt_ANY__7373)[4]; -static uint8_t const unicode_native_endian__7595; -static uint32_t const unicode_replacement_character__7596; -static uint8_t const c_MARKER_TYPE_SAMPLE_START__247; -static uint8_t const c_MARKER_TYPE_SAMPLE_END__248; -static uint8_t const c_MARKER_TYPE_BENCHMARK_START__249; -static uint8_t const c_MARKER_TYPE_BENCHMARK_END__250; -static struct mem_Allocator_VTable__568 const heap_CAllocator_vtable__3565; -zig_extern uintptr_t malloc_usable_size(void const *); -static bool const heap_CAllocator_supports_malloc_size__3566; -static bool const heap_CAllocator_supports_posix_memalign__3568; -zig_extern int posix_memalign(void **, uintptr_t, uintptr_t); -zig_extern void free(void *); -static struct Target_Cpu_Model__812 const Target_x86_cpu_alderlake__3597; -enum { - zig_error_OutOfMemory = 1u, - zig_error_PermissionDenied = 2u, - zig_error_FileNotFound = 3u, - zig_error_NameTooLong = 4u, - zig_error_InputOutput = 5u, - zig_error_SystemResources = 6u, - zig_error_BadPathName = 7u, - zig_error_FileBusy = 8u, - zig_error_SymLinkLoop = 9u, - zig_error_ReadOnlyFileSystem = 10u, - zig_error_InvalidUtf8 = 11u, - zig_error_InvalidWtf8 = 12u, - zig_error_Unexpected = 13u, - zig_error_SharingViolation = 14u, - zig_error_PathAlreadyExists = 15u, - zig_error_AccessDenied = 16u, - zig_error_PipeBusy = 17u, - zig_error_NoDevice = 18u, - zig_error_NetworkNotFound = 19u, - zig_error_AntivirusInterference = 20u, - zig_error_ProcessFdQuotaExceeded = 21u, - zig_error_SystemFdQuotaExceeded = 22u, - zig_error_FileTooBig = 23u, - zig_error_IsDir = 24u, - zig_error_NoSpaceLeft = 25u, - zig_error_NotDir = 26u, - zig_error_DeviceBusy = 27u, - zig_error_FileLocksNotSupported = 28u, - zig_error_WouldBlock = 29u, - zig_error_DiskQuota = 30u, - zig_error_InvalidArgument = 31u, - zig_error_BrokenPipe = 32u, - zig_error_OperationAborted = 33u, - zig_error_NotOpenForWriting = 34u, - zig_error_LockViolation = 35u, - zig_error_ConnectionResetByPeer = 36u, - zig_error_ProcessNotFound = 37u, - zig_error_AckTimeout = 38u, - zig_error_ConnectionTimedOut = 39u, - zig_error_NotOpenForReading = 40u, - zig_error_SocketNotConnected = 41u, - zig_error_Canceled = 42u, - zig_error_NotReady = 43u, - zig_error_UnexpectedEof = 44u, - zig_error_EndOfStream = 45u, - zig_error_UnexpectedError = 46u, - zig_error_UnexpectedResponse = 47u, - zig_error_UnsupportedClock = 48u, - zig_error_Overflow = 49u, - zig_error_Utf8ExpectedContinuation = 50u, - zig_error_Utf8OverlongEncoding = 51u, - zig_error_Utf8EncodesSurrogateHalf = 52u, - zig_error_Utf8CodepointTooLarge = 53u, - zig_error_Utf8InvalidStartByte = 54u, - zig_error_TruncatedInput = 55u, - zig_error_Utf8CannotEncodeSurrogateHalf = 56u, - zig_error_CodepointTooLarge = 57u, -}; -static uint8_t const zig_errorName_OutOfMemory[12] = "OutOfMemory"; -static uint8_t const zig_errorName_PermissionDenied[17] = "PermissionDenied"; -static uint8_t const zig_errorName_FileNotFound[13] = "FileNotFound"; -static uint8_t const zig_errorName_NameTooLong[12] = "NameTooLong"; -static uint8_t const zig_errorName_InputOutput[12] = "InputOutput"; -static uint8_t const zig_errorName_SystemResources[16] = "SystemResources"; -static uint8_t const zig_errorName_BadPathName[12] = "BadPathName"; -static uint8_t const zig_errorName_FileBusy[9] = "FileBusy"; -static uint8_t const zig_errorName_SymLinkLoop[12] = "SymLinkLoop"; -static uint8_t const zig_errorName_ReadOnlyFileSystem[19] = "ReadOnlyFileSystem"; -static uint8_t const zig_errorName_InvalidUtf8[12] = "InvalidUtf8"; -static uint8_t const zig_errorName_InvalidWtf8[12] = "InvalidWtf8"; -static uint8_t const zig_errorName_Unexpected[11] = "Unexpected"; -static uint8_t const zig_errorName_SharingViolation[17] = "SharingViolation"; -static uint8_t const zig_errorName_PathAlreadyExists[18] = "PathAlreadyExists"; -static uint8_t const zig_errorName_AccessDenied[13] = "AccessDenied"; -static uint8_t const zig_errorName_PipeBusy[9] = "PipeBusy"; -static uint8_t const zig_errorName_NoDevice[9] = "NoDevice"; -static uint8_t const zig_errorName_NetworkNotFound[16] = "NetworkNotFound"; -static uint8_t const zig_errorName_AntivirusInterference[22] = "AntivirusInterference"; -static uint8_t const zig_errorName_ProcessFdQuotaExceeded[23] = "ProcessFdQuotaExceeded"; -static uint8_t const zig_errorName_SystemFdQuotaExceeded[22] = "SystemFdQuotaExceeded"; -static uint8_t const zig_errorName_FileTooBig[11] = "FileTooBig"; -static uint8_t const zig_errorName_IsDir[6] = "IsDir"; -static uint8_t const zig_errorName_NoSpaceLeft[12] = "NoSpaceLeft"; -static uint8_t const zig_errorName_NotDir[7] = "NotDir"; -static uint8_t const zig_errorName_DeviceBusy[11] = "DeviceBusy"; -static uint8_t const zig_errorName_FileLocksNotSupported[22] = "FileLocksNotSupported"; -static uint8_t const zig_errorName_WouldBlock[11] = "WouldBlock"; -static uint8_t const zig_errorName_DiskQuota[10] = "DiskQuota"; -static uint8_t const zig_errorName_InvalidArgument[16] = "InvalidArgument"; -static uint8_t const zig_errorName_BrokenPipe[11] = "BrokenPipe"; -static uint8_t const zig_errorName_OperationAborted[17] = "OperationAborted"; -static uint8_t const zig_errorName_NotOpenForWriting[18] = "NotOpenForWriting"; -static uint8_t const zig_errorName_LockViolation[14] = "LockViolation"; -static uint8_t const zig_errorName_ConnectionResetByPeer[22] = "ConnectionResetByPeer"; -static uint8_t const zig_errorName_ProcessNotFound[16] = "ProcessNotFound"; -static uint8_t const zig_errorName_AckTimeout[11] = "AckTimeout"; -static uint8_t const zig_errorName_ConnectionTimedOut[19] = "ConnectionTimedOut"; -static uint8_t const zig_errorName_NotOpenForReading[18] = "NotOpenForReading"; -static uint8_t const zig_errorName_SocketNotConnected[19] = "SocketNotConnected"; -static uint8_t const zig_errorName_Canceled[9] = "Canceled"; -static uint8_t const zig_errorName_NotReady[9] = "NotReady"; -static uint8_t const zig_errorName_UnexpectedEof[14] = "UnexpectedEof"; -static uint8_t const zig_errorName_EndOfStream[12] = "EndOfStream"; -static uint8_t const zig_errorName_UnexpectedError[16] = "UnexpectedError"; -static uint8_t const zig_errorName_UnexpectedResponse[19] = "UnexpectedResponse"; -static uint8_t const zig_errorName_UnsupportedClock[17] = "UnsupportedClock"; -static uint8_t const zig_errorName_Overflow[9] = "Overflow"; -static uint8_t const zig_errorName_Utf8ExpectedContinuation[25] = "Utf8ExpectedContinuation"; -static uint8_t const zig_errorName_Utf8OverlongEncoding[21] = "Utf8OverlongEncoding"; -static uint8_t const zig_errorName_Utf8EncodesSurrogateHalf[25] = "Utf8EncodesSurrogateHalf"; -static uint8_t const zig_errorName_Utf8CodepointTooLarge[22] = "Utf8CodepointTooLarge"; -static uint8_t const zig_errorName_Utf8InvalidStartByte[21] = "Utf8InvalidStartByte"; -static uint8_t const zig_errorName_TruncatedInput[15] = "TruncatedInput"; -static uint8_t const zig_errorName_Utf8CannotEncodeSurrogateHalf[30] = "Utf8CannotEncodeSurrogateHalf"; -static uint8_t const zig_errorName_CodepointTooLarge[18] = "CodepointTooLarge"; -static struct anon__lazy_57 const zig_errorName[58] = {{zig_errorName_OutOfMemory, 11ul}, {zig_errorName_PermissionDenied, 16ul}, {zig_errorName_FileNotFound, 12ul}, {zig_errorName_NameTooLong, 11ul}, {zig_errorName_InputOutput, 11ul}, {zig_errorName_SystemResources, 15ul}, {zig_errorName_BadPathName, 11ul}, {zig_errorName_FileBusy, 8ul}, {zig_errorName_SymLinkLoop, 11ul}, {zig_errorName_ReadOnlyFileSystem, 18ul}, {zig_errorName_InvalidUtf8, 11ul}, {zig_errorName_InvalidWtf8, 11ul}, {zig_errorName_Unexpected, 10ul}, {zig_errorName_SharingViolation, 16ul}, {zig_errorName_PathAlreadyExists, 17ul}, {zig_errorName_AccessDenied, 12ul}, {zig_errorName_PipeBusy, 8ul}, {zig_errorName_NoDevice, 8ul}, {zig_errorName_NetworkNotFound, 15ul}, {zig_errorName_AntivirusInterference, 21ul}, {zig_errorName_ProcessFdQuotaExceeded, 22ul}, {zig_errorName_SystemFdQuotaExceeded, 21ul}, {zig_errorName_FileTooBig, 10ul}, {zig_errorName_IsDir, 5ul}, {zig_errorName_NoSpaceLeft, 11ul}, {zig_errorName_NotDir, 6ul}, {zig_errorName_DeviceBusy, 10ul}, {zig_errorName_FileLocksNotSupported, 21ul}, {zig_errorName_WouldBlock, 10ul}, {zig_errorName_DiskQuota, 9ul}, {zig_errorName_InvalidArgument, 15ul}, {zig_errorName_BrokenPipe, 10ul}, {zig_errorName_OperationAborted, 16ul}, {zig_errorName_NotOpenForWriting, 17ul}, {zig_errorName_LockViolation, 13ul}, {zig_errorName_ConnectionResetByPeer, 21ul}, {zig_errorName_ProcessNotFound, 15ul}, {zig_errorName_AckTimeout, 10ul}, {zig_errorName_ConnectionTimedOut, 18ul}, {zig_errorName_NotOpenForReading, 17ul}, {zig_errorName_SocketNotConnected, 18ul}, {zig_errorName_Canceled, 8ul}, {zig_errorName_NotReady, 8ul}, {zig_errorName_UnexpectedEof, 13ul}, {zig_errorName_EndOfStream, 11ul}, {zig_errorName_UnexpectedError, 15ul}, {zig_errorName_UnexpectedResponse, 18ul}, {zig_errorName_UnsupportedClock, 16ul}, {zig_errorName_Overflow, 8ul}, {zig_errorName_Utf8ExpectedContinuation, 24ul}, {zig_errorName_Utf8OverlongEncoding, 20ul}, {zig_errorName_Utf8EncodesSurrogateHalf, 24ul}, {zig_errorName_Utf8CodepointTooLarge, 21ul}, {zig_errorName_Utf8InvalidStartByte, 20ul}, {zig_errorName_TruncatedInput, 14ul}, {zig_errorName_Utf8CannotEncodeSurrogateHalf, 29ul}, {zig_errorName_CodepointTooLarge, 17ul}}; - -static uint8_t const __anon_1845[21] = "/tmp/runner.ctl.fifo"; - -static uint8_t const __anon_1916[21] = "/tmp/runner.ack.fifo"; - -static uint8_t const __anon_2757[70] = "[ERROR] instrument-hooks: failed to communicate with CodSpeed runner\n"; - -static uint8_t const __anon_2761[83] = "[ERROR] instrument-hooks: please update the CodSpeed action to the latest version\n"; - -static uint8_t const __anon_3003[89] = "Invalid protocol detected: The stream end was found before all required bytes were read."; - -static uint8_t const __anon_4667[10] = "Metadata: "; - -static uint8_t const __anon_4948[1] = " "; - -static uint8_t const __anon_4968[1] = "\000"; - -static uint8_t const __anon_5138[3] = "\357\277\275"; - -static uint8_t const __anon_5013[4] = "any"; - -static uint8_t const __anon_5291[10] = "alderlake"; - -void c_instrument_hooks_set_feature__238(uint64_t const a0, bool const a1) { - uint64_t t0; - t0 = a0; - features_set_feature__325(t0, a1); - return; -} - -static void features_set_feature__325(uint64_t const a0, bool const a1) { - uint64_t t0; - uintptr_t t1; - if (a1) { - t0 = a0; - t1 = t0; - bit_set_IntegerBitSet_2864_29_set__364(&features_features__324, t1); - goto zig_block_0; - } - t0 = a0; - t1 = t0; - bit_set_IntegerBitSet_2864_29_unset__366(&features_features__324, t1); - goto zig_block_0; - - zig_block_0:; - return; -} - -static void bit_set_IntegerBitSet_2864_29_set__364(uint64_t *const a0, uintptr_t const a1) { - uint64_t *const *t1; - uint64_t t2; - uint64_t t5; - uint64_t *t4; - uint64_t *t0; - bool t3; - t0 = a0; - t1 = (uint64_t *const *)&t0; - t2 = a1; - t3 = t2 < UINT64_C(64); - debug_assert__180(t3); - t4 = (*t1); - t4 = (uint64_t *)((uint8_t *)t4 + (uintptr_t)0ul); - t2 = (*t4); - t5 = bit_set_IntegerBitSet_2864_29_maskBit__385(a1); - t5 = t2 | t5; - (*t4) = t5; - return; -} - -static void bit_set_IntegerBitSet_2864_29_unset__366(uint64_t *const a0, uintptr_t const a1) { - uint64_t *const *t1; - uint64_t t2; - uint64_t t5; - uint64_t *t4; - uint64_t *t0; - bool t3; - t0 = a0; - t1 = (uint64_t *const *)&t0; - t2 = a1; - t3 = t2 < UINT64_C(64); - debug_assert__180(t3); - t4 = (*t1); - t4 = (uint64_t *)((uint8_t *)t4 + (uintptr_t)0ul); - t2 = (*t4); - t5 = bit_set_IntegerBitSet_2864_29_maskBit__385(a1); - t5 = zig_not_u64(t5, UINT8_C(64)); - t5 = t2 & t5; - (*t4) = t5; - return; -} - -static void debug_assert__180(bool const a0) { - bool t0; - t0 = !a0; - if (t0) { - zig_unreachable(); - } - goto zig_block_0; - - zig_block_0:; - return; -} - -static uint64_t bit_set_IntegerBitSet_2864_29_maskBit__385(uintptr_t const a0) { - uint64_t t1; - uint8_t t0; - t0 = (uint8_t)a0; - t1 = zig_shlw_u64(UINT64_C(1), t0, UINT8_C(64)); - return t1; -} - -static nav__1074_39 fifo_UnixPipe_openPipe__1074(nav__1074_41 const a0) { - nav__1074_39 t1; - struct fs_File__608 t2; - int32_t t3; - uint16_t t0; - t0 = fs_accessAbsolute__1142(a0, (struct fs_File_OpenFlags__1858){UINT8_C(2),UINT8_C(0),false,false}); - if (t0) { - t1.payload = (struct fs_File__608){-INT32_C(0x55555556)}; - t1.error = t0; - return t1; - } - t1 = fs_openFileAbsolute__1139(a0, (struct fs_File_OpenFlags__1858){UINT8_C(2),UINT8_C(0),false,false}); - if (t1.error) { - t0 = t1.error; - t1.payload = (struct fs_File__608){-INT32_C(0x55555556)}; - t1.error = t0; - return t1; - } - t2 = t1.payload; - t3 = t2.handle; - utils_setNonBlocking__3833(t3); - t1.payload = t2; - t1.error = UINT16_C(0); - return t1; -} - -static nav__1076_39 fifo_UnixPipe_openWrite__1076(struct mem_Allocator__565 const a0, nav__1076_42 const a1) { - nav__1076_39 t2; - struct fifo_UnixPipe_Writer__600 t4; - nav__1076_54 t0; - struct fs_File__608 t3; - uint16_t t1; - t0 = fifo_UnixPipe_openPipe__1074(a1); - if (t0.error) { - t1 = t0.error; - t2.payload = (struct fifo_UnixPipe_Writer__600){{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}}; - t2.error = t1; - return t2; - } - t3 = t0.payload; - t4 = fifo_UnixPipe_Writer_init__1077(t3, a0); - t2.payload = t4; - t2.error = UINT16_C(0); - return t2; -} - -static nav__1075_39 fifo_UnixPipe_openRead__1075(struct mem_Allocator__565 const a0, nav__1075_42 const a1) { - nav__1075_39 t2; - struct fifo_UnixPipe_Reader__602 t4; - nav__1075_54 t0; - struct fs_File__608 t3; - uint16_t t1; - t0 = fifo_UnixPipe_openPipe__1074(a1); - if (t0.error) { - t1 = t0.error; - t2.payload = (struct fifo_UnixPipe_Reader__602){{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}}; - t2.error = t1; - return t2; - } - t3 = t0.payload; - t4 = fifo_UnixPipe_Reader_init__1082(t3, a0); - t2.payload = t4; - t2.error = UINT16_C(0); - return t2; -} - -static nav__751_39 instruments_perf_PerfInstrument_init__751(struct mem_Allocator__565 const a0) { - struct instruments_perf_PerfInstrument__559 *t1; - struct mem_Allocator__565 *t2; - struct fifo_UnixPipe_Writer__600 *t3; - nav__751_61 t4; - nav__751_39 t6; - nav__751_39 t0; - struct fifo_UnixPipe_Writer__600 t7; - struct fifo_UnixPipe_Reader__602 *t8; - nav__751_66 t9; - struct fifo_UnixPipe_Reader__602 t10; - uint16_t t5; - t0.error = UINT16_C(0); - t1 = &t0.payload; - t2 = (struct mem_Allocator__565 *)&t1->allocator; - (*t2) = a0; - t3 = (struct fifo_UnixPipe_Writer__600 *)&t1->writer; - t4 = fifo_UnixPipe_openWrite__1076(a0, (nav__751_59){(uint8_t const *)&__anon_1845,(uintptr_t)20ul}); - if (t4.error) { - t5 = t4.error; - t6.payload = (struct instruments_perf_PerfInstrument__559){{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}},{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}}}; - t6.error = t5; - return t6; - } - t7 = t4.payload; - (*t3) = t7; - t8 = (struct fifo_UnixPipe_Reader__602 *)&t1->reader; - t9 = fifo_UnixPipe_openRead__1075(a0, (nav__751_59){(uint8_t const *)&__anon_1916,(uintptr_t)20ul}); - if (t9.error) { - t5 = t9.error; - t6.payload = (struct instruments_perf_PerfInstrument__559){{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}},{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)},{-INT32_C(0x55555556)}}}; - t6.error = t5; - return t6; - } - t10 = t9.payload; - (*t8) = t10; - return t0; -} - -static nav__726_39 instruments_root_InstrumentHooks_init__726(struct mem_Allocator__565 const a0) { - struct instruments_valgrind_ValgrindInstrument__554 t2; - struct instruments_root_InstrumentHooks__547 t3; - nav__726_39 t4; - struct instruments_perf_PerfInstrument__559 t6; - struct instruments_perf_PerfInstrument__559 t8; - struct instruments_perf_PerfInstrument__559 t5; - nav__726_60 t7; - uint8_t t0; - bool t1; - t0 = running_on_valgrind(); - t1 = t0 > UINT8_C(0); - if (t1) { - t2 = instruments_valgrind_ValgrindInstrument_init__739(a0); - t3.tag = UINT8_C(0); - t3.payload.valgrind = t2; - t4.payload = t3; - t4.error = UINT16_C(0); - return t4; - } - goto zig_block_0; - - zig_block_0:; - t7 = instruments_perf_PerfInstrument_init__751(a0); - t1 = t7.error == UINT16_C(0); - if (t1) { - t8 = t7.payload; - t6 = t8; - goto zig_block_1; - } - return (nav__726_39){{{{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)}}},UINT8_C(2)},0}; - - zig_block_1:; - t5 = t6; - t1 = instruments_perf_PerfInstrument_is_instrumented__754(&t5); - if (t1) { - t6 = t5; - t3.tag = UINT8_C(1); - t3.payload.perf = t6; - t4.payload = t3; - t4.error = UINT16_C(0); - return t4; - } - goto zig_block_2; - - zig_block_2:; - return (nav__726_39){{{{{((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul)}}},UINT8_C(2)},0}; -} - -static uint16_t fifo_UnixPipe_Writer_sendCmd__1080(struct fifo_UnixPipe_Writer__600 *const a0, struct shared_Command__1946 const a1) { - struct fifo_UnixPipe_Writer__600 *const *t1; - struct mem_Allocator__565 *t3; - struct mem_Allocator__565 t4; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t5; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t2; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t6; - nav__1080_60 t8; - struct fifo_UnixPipe_Writer__600 *t9; - struct fifo_UnixPipe_Writer__600 *t0; - struct fs_File__608 *t10; - uintptr_t t12; - uint32_t const *t15; - uint8_t const (*t16)[4]; - nav__1080_44 t17; - struct fs_File__608 t11; - uint32_t t13; - uint32_t t14; - uint16_t t7; - t0 = a0; - t1 = (struct fifo_UnixPipe_Writer__600 *const *)&t0; - t3 = (struct mem_Allocator__565 *)&a0->allocator; - t4 = (*t3); - t5 = array_list_ArrayListAligned_28u8_2cnull_29_init__3888(t4); - t2 = t5; - t6 = array_list_ArrayListAligned_28u8_2cnull_29_writer__3913(&t2); - t7 = bincode_serialize__anon_2015__4061(t6, a1); - if (t7) { - t5 = t2; - array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(t5); - return t7; - } - t5 = t2; - t8 = t5.items; - t9 = (*t1); - t10 = (struct fs_File__608 *)&t9->file; - t11 = (*t10); - t12 = t8.len; - t13 = (uint32_t)t12; - t14 = t13; - t15 = (uint32_t const *)&t14; - t16 = mem_asBytes__anon_2057__4062(t15); - t17.ptr = &(*t16)[(uintptr_t)0ul]; - t17.len = (uintptr_t)4ul; - t7 = fs_File_writeAll__1233(t11, t17); - if (t7) { - t5 = t2; - array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(t5); - return t7; - } - t9 = (*t1); - t10 = (struct fs_File__608 *)&t9->file; - t11 = (*t10); - memcpy(&t17, &t8, sizeof(nav__1080_44)); - t7 = fs_File_writeAll__1233(t11, t17); - if (t7) { - t5 = t2; - array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(t5); - return t7; - } - t5 = t2; - array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(t5); - return 0; -} - -static nav__4173_38 bincode_deserializeInt__anon_2322__4173(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0) { - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t1; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t4; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t2; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t0; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t3; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *t5; - void const **t7; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t8; - void const *t9; - nav__4173_50 (**t10)(void const *, nav__4173_52); - struct io_Reader__2337 t11; - struct io_Reader__2337 t6; - struct io_Reader__2337 t12; - struct io_Reader__2337 t15; - struct io_Reader__2337 const *t13; - uint8_t const (*t21)[4]; - nav__4173_38 t14; - nav__4173_38 t18; - uint32_t t22; - nav__4173_64 t16; - uint16_t t17; - uint8_t t19[4]; - uint8_t t20[4]; - t0 = a0; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t0; - t2 = (*t1); - t3 = t2; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t3; - t4 = t1; - t5 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *)&t4; - t7 = (void const **)&t6.context; - t1 = (*t5); - t8 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t1->context; - t9 = (void const *)t8; - (*t7) = t9; - t10 = (nav__4173_50 (**)(void const *, nav__4173_52))&t6.readFn; - (*t10) = &io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169; - t11 = t6; - t12 = t11; - t13 = (struct io_Reader__2337 const *)&t12; - t11 = (*t13); - t15 = t11; - t13 = (struct io_Reader__2337 const *)&t15; - t11 = (*t13); - t16 = io_Reader_readBytesNoEof__anon_2368__4211(t11); - if (t16.error) { - t17 = t16.error; - t18.payload = UINT32_C(0xaaaaaaaa); - t18.error = t17; - t14 = t18; - goto zig_block_0; - } - memcpy(t19, t16.payload, sizeof(uint8_t[4])); - memcpy((char *)&t20, t19, sizeof(uint8_t[4])); - t21 = (uint8_t const (*)[4])&t20; - memcpy(t19, (const char *)t21, sizeof(uint8_t[4])); - memcpy(&t22, &t19, sizeof(uint32_t)); - t22 = zig_wrap_u32(t22, UINT8_C(32)); - t18.payload = t22; - t18.error = UINT16_C(0); - t14 = t18; - goto zig_block_0; - - zig_block_0:; - memcpy(&t18, &t14, sizeof(nav__4173_38)); - if (t18.error) { - t17 = t18.error; - t18.payload = UINT32_C(0xaaaaaaaa); - t18.error = t17; - return t18; - } - t22 = t18.payload; - t18.payload = t22; - t18.error = UINT16_C(0); - return t18; -} - -static nav__4172_38 bincode_deserializeAlloc__anon_2311__4172(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4172_38 t0; - uint32_t t2; - uint16_t t1; - (void)a1; - t0 = bincode_deserializeInt__anon_2322__4173(a0); - if (t0.error) { - t1 = t0.error; - t0.payload = UINT32_C(0xaaaaaaaa); - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__4215_40 bincode_deserializePointerAlloc__anon_2448__4215(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t1; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t6; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t7; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t32; - struct mem_Allocator__565 const *t3; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t4; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t0; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t5; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t31; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *t8; - void const **t10; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t11; - void const *t12; - nav__4215_59 (**t13)(void const *, nav__4215_39); - struct io_Reader__2337 t14; - struct io_Reader__2337 t9; - struct io_Reader__2337 t15; - struct io_Reader__2337 t18; - struct io_Reader__2337 t33; - struct io_Reader__2337 t34; - struct io_Reader__2337 const *t16; - nav__4215_69 t17; - nav__4215_69 t21; - uint8_t const (*t24)[8]; - uint64_t t25; - uint64_t t38; - nav__4215_40 t26; - uintptr_t t27; - uintptr_t t37; - struct mem_Allocator__565 t29; - struct mem_Allocator__565 t2; - nav__4215_39 t30; - nav__4215_39 t28; - nav__4215_59 t35; - nav__4215_59 t36; - nav__4215_72 t19; - uint16_t t20; - uint8_t t22[8]; - uint8_t t23[8]; - bool t39; - t0 = a0; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t0; - t2 = a1; - t3 = (struct mem_Allocator__565 const *)&t2; - t4 = (*t1); - t5 = t4; - t6 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t5; - t7 = t6; - t8 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *)&t7; - t10 = (void const **)&t9.context; - t6 = (*t8); - t11 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t6->context; - t12 = (void const *)t11; - (*t10) = t12; - t13 = (nav__4215_59 (**)(void const *, nav__4215_39))&t9.readFn; - (*t13) = &io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169; - t14 = t9; - t15 = t14; - t16 = (struct io_Reader__2337 const *)&t15; - t14 = (*t16); - t18 = t14; - t16 = (struct io_Reader__2337 const *)&t18; - t14 = (*t16); - t19 = io_Reader_readBytesNoEof__anon_2461__4216(t14); - if (t19.error) { - t20 = t19.error; - t21.payload = UINT64_C(0xaaaaaaaaaaaaaaaa); - t21.error = t20; - t17 = t21; - goto zig_block_0; - } - memcpy(t22, t19.payload, sizeof(uint8_t[8])); - memcpy((char *)&t23, t22, sizeof(uint8_t[8])); - t24 = (uint8_t const (*)[8])&t23; - memcpy(t22, (const char *)t24, sizeof(uint8_t[8])); - memcpy(&t25, &t22, sizeof(uint64_t)); - t25 = zig_wrap_u64(t25, UINT8_C(64)); - t21.payload = t25; - t21.error = UINT16_C(0); - t17 = t21; - goto zig_block_0; - - zig_block_0:; - memcpy(&t21, &t17, sizeof(nav__4215_69)); - if (t21.error) { - t20 = t21.error; - t26.payload = (nav__4215_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t26.error = t20; - return t26; - } - t25 = t21.payload; - t27 = t25; - t29 = (*t3); - t26 = mem_Allocator_alloc__anon_2153__4103(t29, t27); - if (t26.error) { - t20 = t26.error; - t26.payload = (nav__4215_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t26.error = t20; - return t26; - } - t30 = t26.payload; - t28 = t30; - t4 = (*t1); - t30 = t28; - t31 = t4; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t31; - t32 = t1; - t8 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *)&t32; - t10 = (void const **)&t33.context; - t1 = (*t8); - t11 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t1->context; - t12 = (void const *)t11; - (*t10) = t12; - t13 = (nav__4215_59 (**)(void const *, nav__4215_39))&t33.readFn; - (*t13) = &io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169; - t14 = t33; - t34 = t14; - t16 = (struct io_Reader__2337 const *)&t34; - t14 = (*t16); - t35 = io_Reader_readAll__4176(t14, t30); - memcpy(&t36, &t35, sizeof(nav__4215_59)); - t37 = t36.payload; - t25 = t37; - t38 = t27; - t39 = t25 != t38; - if (t39) { - bincode_invalidProtocol__anon_2485__4217(); - zig_unreachable(); - } - goto zig_block_1; - - zig_block_1:; - t30 = t28; - t26.payload = t30; - t26.error = UINT16_C(0); - return t26; -} - -static nav__4214_40 bincode_deserializeAlloc__anon_2435__4214(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4214_57 t0; - nav__4214_40 t2; - nav__4214_55 t3; - nav__4214_39 t4; - uint16_t t1; - t0 = bincode_deserializePointerAlloc__anon_2448__4215(a0, a1); - if (t0.error) { - t1 = t0.error; - t2.payload = (nav__4214_39){(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t2.error = t1; - return t2; - } - t3 = t0.payload; - memcpy(&t4, &t3, sizeof(nav__4214_39)); - t2.payload = t4; - t2.error = UINT16_C(0); - return t2; -} - -static nav__4213_39 bincode_deserializeStructAlloc__anon_2410__4213(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - uint32_t *t1; - nav__4213_39 t4; - nav__4213_44 *t6; - nav__4213_60 t7; - nav__4213_44 t8; - struct shared_Command__struct_1949__1949 t9; - struct shared_Command__struct_1949__1949 t0; - nav__4213_57 t2; - uint32_t t5; - uint16_t t3; - t1 = (uint32_t *)&t0.pid; - t2 = bincode_deserializeAlloc__anon_2311__4172(a0, a1); - if (t2.error) { - t3 = t2.error; - t4.payload = (struct shared_Command__struct_1949__1949){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}; - t4.error = t3; - return t4; - } - t5 = t2.payload; - (*t1) = t5; - t6 = (nav__4213_44 *)&t0.uri; - t7 = bincode_deserializeAlloc__anon_2435__4214(a0, a1); - if (t7.error) { - t3 = t7.error; - t4.payload = (struct shared_Command__struct_1949__1949){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}; - t4.error = t3; - return t4; - } - t8 = t7.payload; - (*t6) = t8; - t9 = t0; - t4.payload = t9; - t4.error = UINT16_C(0); - return t4; -} - -static nav__4212_39 bincode_deserializeAlloc__anon_2381__4212(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4212_39 t0; - struct shared_Command__struct_1949__1949 t2; - uint16_t t1; - t0 = bincode_deserializeStructAlloc__anon_2410__4213(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (struct shared_Command__struct_1949__1949){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static uint16_t bincode_deserializeAlloc__anon_2500__4218(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - (void)a0; - (void)a1; - return 0; -} - -static nav__4220_39 bincode_deserializeStructAlloc__anon_2564__4220(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4220_44 *t1; - nav__4220_57 t2; - nav__4220_39 t4; - nav__4220_44 t5; - struct shared_Command__struct_1950__1950 t6; - struct shared_Command__struct_1950__1950 t0; - uint16_t t3; - t1 = (nav__4220_44 *)&t0.name; - t2 = bincode_deserializeAlloc__anon_2435__4214(a0, a1); - if (t2.error) { - t3 = t2.error; - t4.payload = (struct shared_Command__struct_1950__1950){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}}; - t4.error = t3; - return t4; - } - t5 = t2.payload; - (*t1) = t5; - t1 = (nav__4220_44 *)&t0.version; - t2 = bincode_deserializeAlloc__anon_2435__4214(a0, a1); - if (t2.error) { - t3 = t2.error; - t4.payload = (struct shared_Command__struct_1950__1950){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}}; - t4.error = t3; - return t4; - } - t5 = t2.payload; - (*t1) = t5; - t6 = t0; - t4.payload = t6; - t4.error = UINT16_C(0); - return t4; -} - -static nav__4219_39 bincode_deserializeAlloc__anon_2545__4219(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4219_39 t0; - struct shared_Command__struct_1950__1950 t2; - uint16_t t1; - t0 = bincode_deserializeStructAlloc__anon_2564__4220(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (struct shared_Command__struct_1950__1950){{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__4226_38 bincode_deserializeInt__anon_2687__4226(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0) { - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t1; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *t4; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t2; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t0; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t3; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *t5; - void const **t7; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t8; - void const *t9; - nav__4226_50 (**t10)(void const *, nav__4226_52); - struct io_Reader__2337 t11; - struct io_Reader__2337 t6; - struct io_Reader__2337 t12; - struct io_Reader__2337 t15; - struct io_Reader__2337 const *t13; - nav__4226_38 t14; - nav__4226_38 t18; - uint8_t const (*t21)[8]; - uint64_t t22; - nav__4226_64 t16; - uint16_t t17; - uint8_t t19[8]; - uint8_t t20[8]; - t0 = a0; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t0; - t2 = (*t1); - t3 = t2; - t1 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *)&t3; - t4 = t1; - t5 = (struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const *const *)&t4; - t7 = (void const **)&t6.context; - t1 = (*t5); - t8 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t1->context; - t9 = (void const *)t8; - (*t7) = t9; - t10 = (nav__4226_50 (**)(void const *, nav__4226_52))&t6.readFn; - (*t10) = &io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169; - t11 = t6; - t12 = t11; - t13 = (struct io_Reader__2337 const *)&t12; - t11 = (*t13); - t15 = t11; - t13 = (struct io_Reader__2337 const *)&t15; - t11 = (*t13); - t16 = io_Reader_readBytesNoEof__anon_2461__4216(t11); - if (t16.error) { - t17 = t16.error; - t18.payload = UINT64_C(0xaaaaaaaaaaaaaaaa); - t18.error = t17; - t14 = t18; - goto zig_block_0; - } - memcpy(t19, t16.payload, sizeof(uint8_t[8])); - memcpy((char *)&t20, t19, sizeof(uint8_t[8])); - t21 = (uint8_t const (*)[8])&t20; - memcpy(t19, (const char *)t21, sizeof(uint8_t[8])); - memcpy(&t22, &t19, sizeof(uint64_t)); - t22 = zig_wrap_u64(t22, UINT8_C(64)); - t18.payload = t22; - t18.error = UINT16_C(0); - t14 = t18; - goto zig_block_0; - - zig_block_0:; - memcpy(&t18, &t14, sizeof(nav__4226_38)); - if (t18.error) { - t17 = t18.error; - t18.payload = UINT64_C(0xaaaaaaaaaaaaaaaa); - t18.error = t17; - return t18; - } - t22 = t18.payload; - t18.payload = t22; - t18.error = UINT16_C(0); - return t18; -} - -static nav__4225_38 bincode_deserializeAlloc__anon_2682__4225(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4225_38 t0; - uint64_t t2; - uint16_t t1; - (void)a1; - t0 = bincode_deserializeInt__anon_2687__4226(a0); - if (t0.error) { - t1 = t0.error; - t0.payload = UINT64_C(0xaaaaaaaaaaaaaaaa); - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__4224_39 bincode_deserializeUnionAlloc__anon_2669__4224(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4224_39 t2; - nav__4224_56 t6; - uint64_t t7; - struct shared_MarkerType__1953 t8; - nav__4224_54 t0; - uint32_t t3; - uint16_t t1; - uint8_t t4; - bool t5; - t0 = bincode_deserializeAlloc__anon_2311__4172(a0, a1); - if (t0.error) { - t1 = t0.error; - t2.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t2.error = t1; - return t2; - } - t3 = t0.payload; - t4 = (uint8_t)t3; - t5 = t4 == UINT8_C(0); - if (t5) { - t6 = bincode_deserializeAlloc__anon_2682__4225(a0, a1); - if (t6.error) { - t1 = t6.error; - t2.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t2.error = t1; - return t2; - } - t7 = t6.payload; - t8.tag = UINT8_C(0); - t8.payload.SampleStart = t7; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_0; - - zig_block_0:; - t5 = t4 == UINT8_C(1); - if (t5) { - t6 = bincode_deserializeAlloc__anon_2682__4225(a0, a1); - if (t6.error) { - t1 = t6.error; - t2.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t2.error = t1; - return t2; - } - t7 = t6.payload; - t8.tag = UINT8_C(1); - t8.payload.SampleEnd = t7; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_1; - - zig_block_1:; - t5 = t4 == UINT8_C(2); - if (t5) { - t6 = bincode_deserializeAlloc__anon_2682__4225(a0, a1); - if (t6.error) { - t1 = t6.error; - t2.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t2.error = t1; - return t2; - } - t7 = t6.payload; - t8.tag = UINT8_C(2); - t8.payload.BenchmarkStart = t7; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_2; - - zig_block_2:; - t5 = t4 == UINT8_C(3); - if (t5) { - t6 = bincode_deserializeAlloc__anon_2682__4225(a0, a1); - if (t6.error) { - t1 = t6.error; - t2.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t2.error = t1; - return t2; - } - t7 = t6.payload; - t8.tag = UINT8_C(3); - t8.payload.BenchmarkEnd = t7; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_3; - - zig_block_3:; - zig_unreachable(); -} - -static nav__4223_39 bincode_deserializeAlloc__anon_2635__4223(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4223_39 t0; - struct shared_MarkerType__1953 t2; - uint16_t t1; - t0 = bincode_deserializeUnionAlloc__anon_2669__4224(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (struct shared_MarkerType__1953){{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__4222_39 bincode_deserializeStructAlloc__anon_2617__4222(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - uint32_t *t1; - nav__4222_39 t4; - struct shared_MarkerType__1953 *t6; - nav__4222_60 t7; - struct shared_MarkerType__1953 t8; - struct shared_Command__struct_1951__1951 t9; - struct shared_Command__struct_1951__1951 t0; - nav__4222_57 t2; - uint32_t t5; - uint16_t t3; - t1 = (uint32_t *)&t0.pid; - t2 = bincode_deserializeAlloc__anon_2311__4172(a0, a1); - if (t2.error) { - t3 = t2.error; - t4.payload = (struct shared_Command__struct_1951__1951){{{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)},UINT32_C(0xaaaaaaaa)}; - t4.error = t3; - return t4; - } - t5 = t2.payload; - (*t1) = t5; - t6 = (struct shared_MarkerType__1953 *)&t0.marker; - t7 = bincode_deserializeAlloc__anon_2635__4223(a0, a1); - if (t7.error) { - t3 = t7.error; - t4.payload = (struct shared_Command__struct_1951__1951){{{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)},UINT32_C(0xaaaaaaaa)}; - t4.error = t3; - return t4; - } - t8 = t7.payload; - (*t6) = t8; - t9 = t0; - t4.payload = t9; - t4.error = UINT16_C(0); - return t4; -} - -static nav__4221_39 bincode_deserializeAlloc__anon_2603__4221(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4221_39 t0; - struct shared_Command__struct_1951__1951 t2; - uint16_t t1; - t0 = bincode_deserializeStructAlloc__anon_2617__4222(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (struct shared_Command__struct_1951__1951){{{UINT64_C(0xaaaaaaaaaaaaaaaa)},UINT8_C(0x2)},UINT32_C(0xaaaaaaaa)}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__4171_39 bincode_deserializeUnionAlloc__anon_2306__4171(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4171_39 t2; - nav__4171_68 t6; - struct shared_Command__struct_1949__1949 t7; - struct shared_Command__1946 t8; - nav__4171_70 t9; - struct shared_Command__struct_1950__1950 t10; - nav__4171_72 t11; - struct shared_Command__struct_1951__1951 t12; - nav__4171_74 t13; - uint64_t t14; - nav__4171_66 t0; - uint32_t t3; - uint16_t t1; - uint8_t t4; - bool t5; - t0 = bincode_deserializeAlloc__anon_2311__4172(a0, a1); - if (t0.error) { - t1 = t0.error; - t2.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t2.error = t1; - return t2; - } - t3 = t0.payload; - t4 = (uint8_t)t3; - t5 = t4 == UINT8_C(0); - if (t5) { - t6 = bincode_deserializeAlloc__anon_2381__4212(a0, a1); - if (t6.error) { - t1 = t6.error; - t2.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t2.error = t1; - return t2; - } - t7 = t6.payload; - t8.tag = UINT8_C(0); - t8.payload.ExecutedBenchmark = t7; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_0; - - zig_block_0:; - t5 = t4 == UINT8_C(1); - if (t5) { - (void)bincode_deserializeAlloc__anon_2500__4218(a0, a1); - return (nav__4171_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(1)},0}; - } - goto zig_block_1; - - zig_block_1:; - t5 = t4 == UINT8_C(2); - if (t5) { - (void)bincode_deserializeAlloc__anon_2500__4218(a0, a1); - return (nav__4171_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(2)},0}; - } - goto zig_block_2; - - zig_block_2:; - t5 = t4 == UINT8_C(3); - if (t5) { - (void)bincode_deserializeAlloc__anon_2500__4218(a0, a1); - return (nav__4171_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(3)},0}; - } - goto zig_block_3; - - zig_block_3:; - t5 = t4 == UINT8_C(4); - if (t5) { - (void)bincode_deserializeAlloc__anon_2500__4218(a0, a1); - return (nav__4171_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(4)},0}; - } - goto zig_block_4; - - zig_block_4:; - t5 = t4 == UINT8_C(5); - if (t5) { - t9 = bincode_deserializeAlloc__anon_2545__4219(a0, a1); - if (t9.error) { - t1 = t9.error; - t2.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t2.error = t1; - return t2; - } - t10 = t9.payload; - t8.tag = UINT8_C(5); - t8.payload.SetIntegration = t10; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_5; - - zig_block_5:; - t5 = t4 == UINT8_C(6); - if (t5) { - (void)bincode_deserializeAlloc__anon_2500__4218(a0, a1); - return (nav__4171_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(6)},0}; - } - goto zig_block_6; - - zig_block_6:; - t5 = t4 == UINT8_C(7); - if (t5) { - t11 = bincode_deserializeAlloc__anon_2603__4221(a0, a1); - if (t11.error) { - t1 = t11.error; - t2.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t2.error = t1; - return t2; - } - t12 = t11.payload; - t8.tag = UINT8_C(7); - t8.payload.AddMarker = t12; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_7; - - zig_block_7:; - t5 = t4 == UINT8_C(8); - if (t5) { - t13 = bincode_deserializeAlloc__anon_2682__4225(a0, a1); - if (t13.error) { - t1 = t13.error; - t2.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t2.error = t1; - return t2; - } - t14 = t13.payload; - t8.tag = UINT8_C(8); - t8.payload.SetVersion = t14; - t2.payload = t8; - t2.error = UINT16_C(0); - return t2; - } - goto zig_block_8; - - zig_block_8:; - zig_unreachable(); -} - -static nav__4170_39 bincode_deserializeAlloc__anon_2209__4170(struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 const a0, struct mem_Allocator__565 const a1) { - nav__4170_39 t0; - struct shared_Command__1946 t2; - uint16_t t1; - t0 = bincode_deserializeUnionAlloc__anon_2306__4171(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static nav__1085_39 fifo_UnixPipe_Reader_recvCmd__1085(struct fifo_UnixPipe_Reader__602 *const a0) { - struct fifo_UnixPipe_Reader__602 *const *t1; - uintptr_t t3; - uintptr_t t10; - struct fifo_UnixPipe_Reader__602 *t4; - struct fifo_UnixPipe_Reader__602 *t0; - struct fs_File__608 *t5; - nav__1085_71 t7; - nav__1085_74 t8; - nav__1085_39 t12; - nav__1085_39 t13; - uint64_t t14; - uint64_t t21; - uint8_t const (*t15)[4]; - struct mem_Allocator__565 *t18; - struct mem_Allocator__565 t19; - nav__1085_78 t20; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t23; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t22; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t24; - struct shared_Command__1946 t25; - struct fs_File__608 t6; - uint32_t t17; - uint16_t t11; - bool t9; - uint8_t t16[4]; - uint8_t t2[4]; - t0 = a0; - t1 = (struct fifo_UnixPipe_Reader__602 *const *)&t0; - t4 = (*t1); - t5 = (struct fs_File__608 *)&t4->file; - t6 = (*t5); - t7.ptr = &t2[(uintptr_t)0ul]; - t7.len = (uintptr_t)4ul; - t8 = fs_File_readAll__1223(t6, t7); - t9 = t8.error == UINT16_C(0); - if (t9) { - t10 = t8.payload; - t3 = t10; - goto zig_block_0; - } - t11 = t8.error; - switch (t11) { - case zig_error_WouldBlock: - case zig_error_BrokenPipe: { - t12 = (nav__1085_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)},zig_error_NotReady}; - goto zig_block_1; - } - default: { - t13.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t13.error = t11; - t12 = t13; - goto zig_block_1; - } - } - - zig_block_1:; - return t12; - - zig_block_0:; - t14 = t3; - t9 = t14 < UINT64_C(4); - if (t9) { - return (nav__1085_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)},zig_error_UnexpectedEof}; - } - goto zig_block_2; - - zig_block_2:; - t15 = (uint8_t const (*)[4])&t2; - memcpy(t16, (const char *)t15, sizeof(uint8_t[4])); - memcpy(&t17, &t16, sizeof(uint32_t)); - t17 = zig_wrap_u32(t17, UINT8_C(32)); - t4 = (*t1); - t18 = (struct mem_Allocator__565 *)&t4->allocator; - t19 = (*t18); - t3 = (uintptr_t)t17; - t20 = mem_Allocator_alloc__anon_2153__4103(t19, t3); - if (t20.error) { - t11 = t20.error; - t13.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t13.error = t11; - return t13; - } - t7 = t20.payload; - t4 = (*t1); - t5 = (struct fs_File__608 *)&t4->file; - t6 = (*t5); - t8 = fs_File_readAll__1223(t6, t7); - t9 = t8.error == UINT16_C(0); - if (t9) { - t10 = t8.payload; - t3 = t10; - goto zig_block_3; - } - t11 = t8.error; - switch (t11) { - case zig_error_WouldBlock: - case zig_error_BrokenPipe: { - t13 = (nav__1085_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)},zig_error_NotReady}; - goto zig_block_4; - } - default: { - t12.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t12.error = t11; - t13 = t12; - goto zig_block_4; - } - } - - zig_block_4:; - t4 = (*t1); - t18 = (struct mem_Allocator__565 *)&t4->allocator; - t19 = (*t18); - mem_Allocator_free__anon_2159__4104(t19, t7); - return t13; - - zig_block_3:; - t14 = t3; - t21 = (uint64_t)t17; - t9 = t14 < t21; - if (t9) { - t4 = (*t1); - t18 = (struct mem_Allocator__565 *)&t4->allocator; - t19 = (*t18); - mem_Allocator_free__anon_2159__4104(t19, t7); - return (nav__1085_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)},zig_error_UnexpectedEof}; - } - goto zig_block_5; - - zig_block_5:; - t23 = io_fixed_buffer_stream_fixedBufferStream__anon_2181__4136(t7); - t22 = t23; - t24 = io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_reader__4125(&t22); - t18 = (struct mem_Allocator__565 *)&a0->allocator; - t19 = (*t18); - t13 = bincode_deserializeAlloc__anon_2209__4170(t24, t19); - if (t13.error) { - t11 = t13.error; - t4 = (*t1); - t18 = (struct mem_Allocator__565 *)&t4->allocator; - t19 = (*t18); - mem_Allocator_free__anon_2159__4104(t19, t7); - t13.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t13.error = t11; - return t13; - } - t25 = t13.payload; - t4 = (*t1); - t18 = (struct mem_Allocator__565 *)&t4->allocator; - t19 = (*t18); - mem_Allocator_free__anon_2159__4104(t19, t7); - t13.payload = t25; - t13.error = UINT16_C(0); - return t13; -} - -static nav__1086_39 fifo_UnixPipe_Reader_waitForResponse__1086(struct fifo_UnixPipe_Reader__602 *const a0, nav__1086_42 const a1) { - zig_i128 t2; - zig_i128 t6; - struct fifo_UnixPipe_Reader__602 *const *t1; - uint64_t t3; - uint64_t t5; - struct shared_Command__1946 t7; - struct shared_Command__1946 t10; - struct fifo_UnixPipe_Reader__602 *t8; - struct fifo_UnixPipe_Reader__602 *t0; - nav__1086_39 t9; - uint16_t t11; - bool t4; - t0 = a0; - t1 = (struct fifo_UnixPipe_Reader__602 *const *)&t0; - t2 = time_nanoTimestamp__4075(); - t4 = a1.is_null != true; - if (t4) { - t5 = a1.payload; - t3 = t5; - goto zig_block_0; - } - t3 = UINT64_C(5000000000); - goto zig_block_0; - - zig_block_0:; - zig_loop_13: - t6 = time_nanoTimestamp__4075(); - t6 = zig_sub_i128(t6, t2); - t5 = zig_lo_i128(t6); - t4 = t5 > t3; - if (t4) { - return (nav__1086_39){{{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)},zig_error_AckTimeout}; - } - goto zig_block_2; - - zig_block_2:; - t8 = (*t1); - t9 = fifo_UnixPipe_Reader_recvCmd__1085(t8); - t4 = t9.error == UINT16_C(0); - if (t4) { - t10 = t9.payload; - t7 = t10; - goto zig_block_3; - } - t11 = t9.error; - switch (t11) { - case zig_error_NotReady: - case zig_error_UnexpectedEof: { - utils_sleep__3832(UINT64_C(10000000)); - goto zig_block_1; - } - default: { - t9.payload = (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(0xa)}; - t9.error = t11; - return t9; - } - } - - zig_block_3:; - t9.payload = t7; - t9.error = UINT16_C(0); - return t9; - - zig_block_1:; - goto zig_loop_13; -} - -static uint16_t fifo_UnixPipe_Reader_waitForAck__1087(struct fifo_UnixPipe_Reader__602 *const a0, nav__1087_40 const a1) { - struct fifo_UnixPipe_Reader__602 *const *t1; - struct fifo_UnixPipe_Reader__602 *t2; - struct fifo_UnixPipe_Reader__602 *t0; - nav__1087_60 t3; - struct shared_Command__1946 t5; - struct shared_Command__1946 t6; - struct shared_Command__1946 const *t7; - struct mem_Allocator__565 *t10; - struct mem_Allocator__565 t11; - uint16_t t4; - uint8_t t8; - bool t9; - t0 = a0; - t1 = (struct fifo_UnixPipe_Reader__602 *const *)&t0; - t2 = (*t1); - t3 = fifo_UnixPipe_Reader_waitForResponse__1086(t2, a1); - if (t3.error) { - t4 = t3.error; - return t4; - } - t5 = t3.payload; - t6 = t5; - t7 = (struct shared_Command__1946 const *)&t6; - t8 = t5.tag; - t9 = t8 == UINT8_C(3); - if (t9) { - t5 = (*t7); - t10 = (struct mem_Allocator__565 *)&a0->allocator; - t11 = (*t10); - shared_Command_deinit__3836(t5, t11); - return 0; - } - t8 = t5.tag; - t9 = t8 == UINT8_C(6); - if (t9) { - t5 = (*t7); - t10 = (struct mem_Allocator__565 *)&a0->allocator; - t11 = (*t10); - shared_Command_deinit__3836(t5, t11); - return zig_error_UnexpectedError; - } - t5 = (*t7); - t10 = (struct mem_Allocator__565 *)&a0->allocator; - t11 = (*t10); - shared_Command_deinit__3836(t5, t11); - return zig_error_UnexpectedResponse; -} - -static uint16_t instruments_perf_PerfInstrument_send_version__760(struct instruments_perf_PerfInstrument__559 *const a0, uint64_t const a1) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct shared_Command__1946 t4; - struct fifo_UnixPipe_Reader__602 *t6; - uint16_t t5; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4.tag = UINT8_C(8); - t4.payload.SetVersion = a1; - t5 = fifo_UnixPipe_Writer_sendCmd__1080(t3, t4); - if (t5) { - return t5; - } - t2 = (*t1); - t6 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t5 = fifo_UnixPipe_Reader_waitForAck__1087(t6, (nav__760_71){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t5) { - return t5; - } - return 0; -} - -struct instruments_root_InstrumentHooks__547 *c_instrument_hooks_init__239(void) { - struct instruments_root_InstrumentHooks__547 *t0; - struct instruments_root_InstrumentHooks__547 *t3; - struct instruments_root_InstrumentHooks__547 *t4; - struct instruments_root_InstrumentHooks__547 *t11; - nav__239_46 t1; - struct instruments_root_InstrumentHooks__547 *const *t5; - nav__239_72 t6; - struct instruments_root_InstrumentHooks__547 t7; - struct instruments_perf_PerfInstrument__559 *t9; - uint16_t t10; - bool t2; - uint8_t t8; - t1 = mem_Allocator_create__anon_858__3577((struct mem_Allocator__565){((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}); - t2 = t1.error == UINT16_C(0); - if (t2) { - t3 = t1.payload; - t0 = t3; - goto zig_block_0; - } - return NULL; - - zig_block_0:; - t4 = t0; - t5 = (struct instruments_root_InstrumentHooks__547 *const *)&t4; - t6 = instruments_root_InstrumentHooks_init__726((struct mem_Allocator__565){((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}); - t7 = t6.payload; - (*t0) = t7; - t7 = (*t0); - t8 = t7.tag; - t2 = t8 == UINT8_C(1); - if (t2) { - t3 = (*t5); - t9 = (struct instruments_perf_PerfInstrument__559 *)&t3->payload.perf; - t10 = instruments_perf_PerfInstrument_send_version__760(t9, UINT64_C(1)); - t2 = t10 == UINT16_C(0); - if (t2) { - goto zig_block_2; - } - (void)printf((char const *)&__anon_2757); - (void)printf((char const *)&__anon_2761); - t3 = (*t5); - t11 = t3; - t5 = (struct instruments_root_InstrumentHooks__547 *const *)&t11; - t7 = (*t3); - t8 = t7.tag; - switch (t8) { - case UINT8_C(0): { - goto zig_block_3; - } - case UINT8_C(1): { - t3 = (*t5); - t9 = (struct instruments_perf_PerfInstrument__559 *)&t3->payload.perf; - instruments_perf_PerfInstrument_deinit__752(t9); - goto zig_block_3; - } - case UINT8_C(2): { - goto zig_block_3; - } - default: zig_unreachable(); - } - - zig_block_3:; - mem_Allocator_destroy__anon_2777__4228((struct mem_Allocator__565){((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}, t0); - posix_exit__1442(UINT8_C(1)); - zig_unreachable(); - - zig_block_2:; - goto zig_block_1; - } - goto zig_block_1; - - zig_block_1:; - t3 = (struct instruments_root_InstrumentHooks__547 *)t0; - return t3; -} - -static nav__3577_40 mem_Allocator_create__anon_858__3577(struct mem_Allocator__565 const a0) { - struct mem_Allocator__565 const *t1; - struct mem_Allocator__565 t2; - struct mem_Allocator__565 t0; - uintptr_t t3; - nav__3577_51 t4; - nav__3577_40 t6; - uint8_t *t7; - struct instruments_root_InstrumentHooks__547 *t8; - uint16_t t5; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = (*t1); - t3 = (uintptr_t)zig_return_address(); - t4 = mem_Allocator_allocBytesWithAlignment__anon_2793__4229(t2, (uintptr_t)72ul, t3); - if (t4.error) { - t5 = t4.error; - t6.payload = ((struct instruments_root_InstrumentHooks__547 *)(uintptr_t)0xaaaaaaaaaaaaaaaaul); - t6.error = t5; - return t6; - } - t7 = t4.payload; - t8 = (struct instruments_root_InstrumentHooks__547 *)t7; - t6.payload = t8; - t6.error = UINT16_C(0); - return t6; -} - -static struct instruments_valgrind_ValgrindInstrument__554 instruments_valgrind_ValgrindInstrument_init__739(struct mem_Allocator__565 const a0) { - struct instruments_valgrind_ValgrindInstrument__554 t0; - t0.allocator = a0; - return t0; -} - -static uint16_t fs_accessAbsolute__1142(nav__1142_39 const a0, struct fs_File_OpenFlags__1858 const a1) { - struct fs_Dir__1860 const *t3; - struct fs_Dir__1860 t1; - struct fs_Dir__1860 t2; - uint16_t t4; - bool t0; - t0 = fs_path_isAbsolute__4264(a0); - debug_assert__180(t0); - t1 = fs_cwd__1134(); - t2 = t1; - t3 = (struct fs_Dir__1860 const *)&t2; - t1 = (*t3); - t4 = fs_Dir_access__3783(t1, a0, a1); - if (t4) { - return t4; - } - return 0; -} - -static nav__1139_39 fs_openFileAbsolute__1139(nav__1139_41 const a0, struct fs_File_OpenFlags__1858 const a1) { - struct fs_Dir__1860 const *t3; - struct fs_Dir__1860 t1; - struct fs_Dir__1860 t2; - nav__1139_39 t4; - bool t0; - t0 = fs_path_isAbsolute__4264(a0); - debug_assert__180(t0); - t1 = fs_cwd__1134(); - t2 = t1; - t3 = (struct fs_Dir__1860 const *)&t2; - t1 = (*t3); - t4 = fs_Dir_openFile__3719(t1, a0, a1); - return t4; -} - -static void utils_setNonBlocking__3833(int32_t const a0) { - int t0; - int t1; - t0 = a0; - t0 = fcntl(t0, 3, 0); - t0 = t0 | 2048; - t1 = a0; - (void)fcntl(t1, 4, t0); - return; -} - -static struct fifo_UnixPipe_Writer__600 fifo_UnixPipe_Writer_init__1077(struct fs_File__608 const a0, struct mem_Allocator__565 const a1) { - struct fs_File__608 *t1; - struct mem_Allocator__565 *t2; - struct fifo_UnixPipe_Writer__600 t0; - t1 = (struct fs_File__608 *)&t0.file; - (*t1) = a0; - t2 = (struct mem_Allocator__565 *)&t0.allocator; - (*t2) = a1; - return t0; -} - -static struct fifo_UnixPipe_Reader__602 fifo_UnixPipe_Reader_init__1082(struct fs_File__608 const a0, struct mem_Allocator__565 const a1) { - struct fs_File__608 *t1; - struct mem_Allocator__565 *t2; - struct fifo_UnixPipe_Reader__602 t0; - t1 = (struct fs_File__608 *)&t0.file; - (*t1) = a0; - t2 = (struct mem_Allocator__565 *)&t0.allocator; - (*t2) = a1; - return t0; -} - -static uint16_t instruments_perf_PerfInstrument_send_cmd__753(struct instruments_perf_PerfInstrument__559 *const a0, struct shared_Command__1946 const a1) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct fifo_UnixPipe_Reader__602 *t5; - uint16_t t4; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4 = fifo_UnixPipe_Writer_sendCmd__1080(t3, a1); - if (t4) { - return t4; - } - t2 = (*t1); - t5 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t4 = fifo_UnixPipe_Reader_waitForAck__1087(t5, (nav__753_72){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t4) { - return t4; - } - return 0; -} - -static bool instruments_perf_PerfInstrument_is_instrumented__754(struct instruments_perf_PerfInstrument__559 *const a0) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - uint16_t t3; - bool t4; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = instruments_perf_PerfInstrument_send_cmd__753(t2, (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(4)}); - t4 = t3 == UINT16_C(0); - if (t4) { - goto zig_block_0; - } - return false; - - zig_block_0:; - return true; -} - -static struct array_list_ArrayListAligned_28u8_2cnull_29__1974 array_list_ArrayListAligned_28u8_2cnull_29_init__3888(struct mem_Allocator__565 const a0) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t0; - t0.items = (nav__3888_42){(uint8_t *)((void const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),(uintptr_t)0ul}; - t0.capacity = (uintptr_t)0ul; - t0.allocator = a0; - return t0; -} - -static struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 array_list_ArrayListAligned_28u8_2cnull_29_writer__3913(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 **t1; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 **)&t0.context; - (*t1) = a0; - return t0; -} - -static uint16_t bincode_serialize__anon_2015__4061(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__1946 const a1) { - uint16_t t0; - t0 = bincode_serializeUnion__anon_2860__5247(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static void array_list_ArrayListAligned_28u8_2cnull_29_deinit__3890(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const a0) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const *t1; - struct mem_Allocator__565 const *t2; - struct mem_Allocator__565 t3; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t4; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t0; - nav__3890_41 t5; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const *)&t0; - t2 = (struct mem_Allocator__565 const *)&t1->allocator; - t3 = (*t2); - t4 = (*t1); - t5 = array_list_ArrayListAligned_28u8_2cnull_29_allocatedSlice__3936(t4); - mem_Allocator_free__anon_2159__4104(t3, t5); - return; -} - -static uint8_t const (*mem_asBytes__anon_2057__4062(uint32_t const *const a0))[4] { - uint8_t const (*t0)[4]; - t0 = (uint8_t const (*)[4])a0; - return t0; -} - -static uint16_t fs_File_writeAll__1233(struct fs_File__608 const a0, nav__1233_40 const a1) { - struct fs_File__608 const *t1; - nav__1233_40 const *t3; - uintptr_t t5; - uintptr_t t6; - uintptr_t t13; - uintptr_t t4; - uint64_t t7; - uint64_t t8; - nav__1233_40 t11; - nav__1233_40 t2; - uint8_t const *t12; - nav__1233_47 t14; - struct fs_File__608 t10; - struct fs_File__608 t0; - uint16_t t15; - bool t9; - t0 = a0; - t1 = (struct fs_File__608 const *)&t0; - t2 = a1; - t3 = (nav__1233_40 const *)&t2; - t4 = (uintptr_t)0ul; - zig_loop_11: - t5 = t4; - t6 = a1.len; - t7 = t5; - t8 = t6; - t9 = t7 < t8; - if (t9) { - t6 = t4; - t10 = (*t1); - t5 = t4; - t11 = (*t3); - t12 = t11.ptr; - t12 = (uint8_t const *)(((uintptr_t)t12) + (t5*sizeof(uint8_t))); - t13 = t11.len; - t5 = t13 - t5; - t11.ptr = t12; - t11.len = t5; - t14 = fs_File_write__1232(t10, t11); - if (t14.error) { - t15 = t14.error; - return t15; - } - t5 = t14.payload; - t5 = t6 + t5; - t4 = t5; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_11; - - zig_block_0:; - return 0; -} - -static zig_i128 time_nanoTimestamp__4075(void) { - zig_i128 t6; - zig_i128 t7; - nav__4075_41 t0; - struct os_linux_timespec__struct_2922__2922 t2; - struct os_linux_timespec__struct_2922__2922 t3; - intptr_t t5; - uint16_t t4; - bool t1; - t0 = posix_clock_gettime__1633(UINT32_C(0)); - t1 = t0.error == UINT16_C(0); - if (t1) { - t3 = t0.payload; - t2 = t3; - goto zig_block_0; - } - t4 = t0.error; - switch (t4) { - case zig_error_UnsupportedClock: - case zig_error_Unexpected: { - return zig_make_i128(INT64_C(0), UINT64_C(0)); - } - default: zig_unreachable(); - } - - zig_block_0:; - t5 = t2.sec; - t6 = zig_make_i128(0, t5); - t6 = zig_mul_i128(t6, zig_make_i128(INT64_C(0), UINT64_C(1000000000))); - t5 = t2.nsec; - t7 = zig_make_i128(0, t5); - t7 = zig_add_i128(t6, t7); - return t7; -} - -static nav__1223_38 fs_File_readAll__1223(struct fs_File__608 const a0, nav__1223_41 const a1) { - struct fs_File__608 const *t1; - nav__1223_41 const *t3; - uintptr_t t5; - uintptr_t t6; - uintptr_t t4; - uint64_t t7; - uint64_t t8; - nav__1223_41 t11; - nav__1223_41 t2; - uint8_t *t12; - nav__1223_38 t13; - struct fs_File__608 t10; - struct fs_File__608 t0; - uint16_t t14; - bool t9; - t0 = a0; - t1 = (struct fs_File__608 const *)&t0; - t2 = a1; - t3 = (nav__1223_41 const *)&t2; - t4 = (uintptr_t)0ul; - zig_loop_11: - t5 = t4; - t6 = a1.len; - t7 = t5; - t8 = t6; - t9 = t7 != t8; - if (t9) { - t10 = (*t1); - t6 = t4; - t11 = (*t3); - t12 = t11.ptr; - t12 = (uint8_t *)(((uintptr_t)t12) + (t6*sizeof(uint8_t))); - t5 = t11.len; - t6 = t5 - t6; - t11.ptr = t12; - t11.len = t6; - t13 = fs_File_read__1222(t10, t11); - if (t13.error) { - t14 = t13.error; - t13.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t13.error = t14; - return t13; - } - t6 = t13.payload; - t8 = t6; - t9 = t8 == UINT64_C(0); - if (t9) { - goto zig_block_0; - } - goto zig_block_2; - - zig_block_2:; - t5 = t4; - t6 = t5 + t6; - t4 = t6; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_11; - - zig_block_0:; - t6 = t4; - t13.payload = t6; - t13.error = UINT16_C(0); - return t13; -} - -static nav__4103_40 mem_Allocator_alloc__anon_2153__4103(struct mem_Allocator__565 const a0, uintptr_t const a1) { - struct mem_Allocator__565 const *t1; - struct mem_Allocator__565 t2; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t5; - uintptr_t t3; - nav__4103_40 t4; - nav__4103_40 t8; - nav__4103_51 t6; - uint8_t *t9; - uint8_t *t10; - uint8_t *const *t11; - nav__4103_39 t12; - uint16_t t7; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = (*t1); - t3 = (uintptr_t)zig_return_address(); - t5 = t2; - t1 = (struct mem_Allocator__565 const *)&t5; - t2 = (*t1); - t6 = mem_Allocator_allocWithSizeAndAlignment__anon_2953__5248(t2, a1, t3); - if (t6.error) { - t7 = t6.error; - t8.payload = (nav__4103_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t8.error = t7; - t4 = t8; - goto zig_block_0; - } - t9 = t6.payload; - t10 = t9; - t11 = (uint8_t *const *)&t10; - t9 = (*t11); - t9 = (uint8_t *)(((uintptr_t)t9) + ((uintptr_t)0ul*sizeof(uint8_t))); - t12.ptr = t9; - t12.len = a1; - t8.payload = t12; - t8.error = UINT16_C(0); - t4 = t8; - goto zig_block_0; - - zig_block_0:; - return t4; -} - -static void mem_Allocator_free__anon_2159__4104(struct mem_Allocator__565 const a0, nav__4104_40 const a1) { - struct mem_Allocator__565 const *t1; - nav__4104_40 t2; - uintptr_t t3; - uint64_t t4; - uint8_t *t6; - uint8_t *t7; - uint8_t *t8; - uint8_t *const *t9; - struct mem_Allocator__565 t10; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t12; - struct mem_Allocator_VTable__568 const *const *t13; - struct mem_Allocator_VTable__568 const *t14; - void (*const *t15)(void *, nav__4104_40, uint8_t, uintptr_t); - void (*t16)(void *, nav__4104_40, uint8_t, uintptr_t); - void *t17; - bool t5; - uint8_t t11; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = mem_sliceAsBytes__anon_2966__5249(a1); - t3 = t2.len; - t4 = t3; - t5 = t4 == UINT64_C(0); - if (t5) { - return; - } - goto zig_block_0; - - zig_block_0:; - t6 = t2.ptr; - t7 = (uint8_t *)t6; - t8 = t7; - t9 = (uint8_t *const *)&t8; - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t2.ptr = t7; - t2.len = t3; - t10 = (*t1); - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t2.ptr = t7; - t2.len = t3; - t11 = mem_Alignment_fromByteUnits__1046((uintptr_t)1ul); - t3 = (uintptr_t)zig_return_address(); - t12 = t10; - t1 = (struct mem_Allocator__565 const *)&t12; - t13 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t14 = (*t13); - t15 = (void (*const *)(void *, nav__4104_40, uint8_t, uintptr_t))&t14->free; - t16 = (*t15); - t17 = t10.ptr; - t16(t17, t2, t11, t3); - return; -} - -static struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 io_fixed_buffer_stream_fixedBufferStream__anon_2181__4136(nav__4136_40 const a0) { - nav__4136_40 *t1; - uintptr_t *t2; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t0; - t1 = (nav__4136_40 *)&t0.buffer; - (*t1) = a0; - t2 = (uintptr_t *)&t0.pos; - (*t2) = (uintptr_t)0ul; - return t0; -} - -static struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_reader__4125(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const a0) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 **t1; - struct io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29__2201 t0; - t1 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 **)&t0.context; - (*t1) = a0; - return t0; -} - -static nav__4169_38 io_GenericReader_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7b_7d_2c_28function_20_27read_27_29_29_typeEras__4169(void const *const a0, nav__4169_41 const a1) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t0; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t1; - nav__4169_38 t2; - nav__4169_38 t3; - t0 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)a0; - t1 = (*t0); - t2 = io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_read__4128(t1, a1); - memcpy(&t3, &t2, sizeof(nav__4169_38)); - return t3; -} - -static nav__4211_39 io_Reader_readBytesNoEof__anon_2368__4211(struct io_Reader__2337 const a0) { - struct io_Reader__2337 const *t1; - struct io_Reader__2337 t3; - struct io_Reader__2337 t0; - nav__4211_46 t4; - uint16_t t5; - nav__4211_39 t6; - uint8_t t7[4]; - uint8_t t2[4]; - t0 = a0; - t1 = (struct io_Reader__2337 const *)&t0; - t3 = (*t1); - t4.ptr = &t2[(uintptr_t)0ul]; - t4.len = (uintptr_t)4ul; - t5 = io_Reader_readNoEof__4178(t3, t4); - if (t5) { - memcpy(t6.payload, "\252\252\252\252", sizeof(uint8_t[4])); - t6.error = t5; - return t6; - } - memcpy(t7, (const char *)&t2, sizeof(uint8_t[4])); - memcpy(t6.payload, t7, sizeof(uint8_t[4])); - t6.error = UINT16_C(0); - return t6; -} - -static nav__4216_39 io_Reader_readBytesNoEof__anon_2461__4216(struct io_Reader__2337 const a0) { - struct io_Reader__2337 const *t1; - struct io_Reader__2337 t3; - struct io_Reader__2337 t0; - nav__4216_46 t4; - uint16_t t5; - nav__4216_39 t6; - uint8_t t7[8]; - uint8_t t2[8]; - t0 = a0; - t1 = (struct io_Reader__2337 const *)&t0; - t3 = (*t1); - t4.ptr = &t2[(uintptr_t)0ul]; - t4.len = (uintptr_t)8ul; - t5 = io_Reader_readNoEof__4178(t3, t4); - if (t5) { - memcpy(t6.payload, "\252\252\252\252\252\252\252\252", sizeof(uint8_t[8])); - t6.error = t5; - return t6; - } - memcpy(t7, (const char *)&t2, sizeof(uint8_t[8])); - memcpy(t6.payload, t7, sizeof(uint8_t[8])); - t6.error = UINT16_C(0); - return t6; -} - -static nav__4176_38 io_Reader_readAll__4176(struct io_Reader__2337 const a0, nav__4176_41 const a1) { - uintptr_t t0; - nav__4176_38 t1; - t0 = a1.len; - t1 = io_Reader_readAtLeast__4177(a0, a1, t0); - return t1; -} - -static zig_cold zig_noreturn void bincode_invalidProtocol__anon_2485__4217(void) { - debug_no_panic_call__5251((nav__4217_40){(uint8_t const *)&__anon_3003,(uintptr_t)88ul}, (nav__4217_42){(uintptr_t)0xaaaaaaaaaaaaaaaaul,true}); - zig_unreachable(); -} - -static void utils_sleep__3832(uint64_t const a0) { - uint64_t t0; - uint64_t t1; - long *t3; - long t4; - long t7; - nav__3832_42 t5; - struct cimport_struct_timespec__3100 const *t9; - struct cimport_struct_timespec__3100 *t10; - struct cimport_struct_timespec__3100 t13; - struct cimport_struct_timespec__3100 t2; - struct cimport_struct_timespec__3100 t8; - int t11; - int32_t t12; - bool t6; - t0 = a0 / UINT64_C(1000000000); - t1 = a0 % UINT64_C(1000000000); - t3 = (long *)&t2.tv_sec; - t5 = math_cast__anon_3113__6121(t0); - t6 = t5.is_null != true; - if (t6) { - t7 = t5.payload; - t4 = t7; - goto zig_block_0; - } - t4 = LONG_MAX; - goto zig_block_0; - - zig_block_0:; - (*t3) = t4; - t3 = (long *)&t2.tv_nsec; - t5 = math_cast__anon_3113__6121(t1); - t6 = t5.is_null != true; - if (t6) { - t7 = t5.payload; - t4 = t7; - goto zig_block_1; - } - t4 = LONG_MAX; - goto zig_block_1; - - zig_block_1:; - (*t3) = t4; - zig_loop_28: - t9 = (struct cimport_struct_timespec__3100 const *)&t2; - t10 = (struct cimport_struct_timespec__3100 *)&t8; - t11 = nanosleep(t9, t10); - t12 = t11; - t6 = t12 == INT32_C(4); - if (t6) { - t13 = t8; - t2 = t13; - goto zig_block_2; - } - return; - - zig_block_2:; - goto zig_loop_28; -} - -static void shared_Command_deinit__3836(struct shared_Command__1946 const a0, struct mem_Allocator__565 const a1) { - struct mem_Allocator__565 const *t1; - struct shared_Command__struct_1950__1950 t3; - struct mem_Allocator__565 t4; - struct mem_Allocator__565 t0; - nav__3836_43 t5; - struct shared_Command__struct_1949__1949 t6; - uint8_t t2; - t0 = a1; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = a0.tag; - switch (t2) { - case UINT8_C(5): { - t3 = a0.payload.SetIntegration; - t4 = (*t1); - t5 = t3.name; - mem_Allocator_free__anon_3185__6890(t4, t5); - t4 = (*t1); - t5 = t3.version; - mem_Allocator_free__anon_3185__6890(t4, t5); - goto zig_block_0; - } - case UINT8_C(0): { - t6 = a0.payload.ExecutedBenchmark; - t4 = (*t1); - t5 = t6.uri; - mem_Allocator_free__anon_3185__6890(t4, t5); - goto zig_block_0; - } - case UINT8_C(8): { - goto zig_block_0; - } - default: { - goto zig_block_0; - } - } - - zig_block_0:; - return; -} - -static void instruments_perf_PerfInstrument_deinit__752(struct instruments_perf_PerfInstrument__559 *const a0) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct fifo_UnixPipe_Reader__602 *t4; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - fifo_UnixPipe_Writer_deinit__1081(t3); - t2 = (*t1); - t4 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - fifo_UnixPipe_Reader_deinit__1088(t4); - return; -} - -static void mem_Allocator_destroy__anon_2777__4228(struct mem_Allocator__565 const a0, struct instruments_root_InstrumentHooks__547 *const a1) { - struct mem_Allocator__565 const *t1; - uint8_t *t2; - uint8_t *t3; - uint8_t *const *t4; - struct mem_Allocator__565 t5; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t10; - uint8_t (*t6)[72]; - nav__4228_52 t7; - uintptr_t t9; - struct mem_Allocator_VTable__568 const *const *t11; - struct mem_Allocator_VTable__568 const *t12; - void (*const *t13)(void *, nav__4228_52, uint8_t, uintptr_t); - void (*t14)(void *, nav__4228_52, uint8_t, uintptr_t); - void *t15; - uint8_t t8; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = (uint8_t *)a1; - t3 = t2; - t4 = (uint8_t *const *)&t3; - t5 = (*t1); - t2 = (*t4); - t2 = (uint8_t *)(((uintptr_t)t2) + ((uintptr_t)0ul*sizeof(uint8_t))); - t6 = (uint8_t (*)[72])t2; - t7.ptr = &(*t6)[(uintptr_t)0ul]; - t7.len = (uintptr_t)72ul; - t8 = mem_Alignment_fromByteUnits__1046((uintptr_t)8ul); - t9 = (uintptr_t)zig_return_address(); - t10 = t5; - t1 = (struct mem_Allocator__565 const *)&t10; - t11 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t12 = (*t11); - t13 = (void (*const *)(void *, nav__4228_52, uint8_t, uintptr_t))&t12->free; - t14 = (*t13); - t15 = t5.ptr; - t14(t15, t7, t8, t9); - return; -} - -static zig_noreturn void posix_exit__1442(uint8_t const a0) { - int t0; - t0 = (int)a0; - exit(t0); - zig_unreachable(); -} - -static nav__4229_39 mem_Allocator_allocBytesWithAlignment__anon_2793__4229(struct mem_Allocator__565 const a0, uintptr_t const a1, uintptr_t const a2) { - struct mem_Allocator__565 const *t1; - uint64_t t2; - uint8_t *t4; - uint8_t *t13; - uint8_t *t14; - uint8_t *t15; - struct mem_Allocator__565 t5; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t7; - struct mem_Allocator_VTable__568 const *const *t8; - struct mem_Allocator_VTable__568 const *t9; - uint8_t *(*const *t10)(void *, uintptr_t, uint8_t, uintptr_t); - uint8_t *(*t11)(void *, uintptr_t, uint8_t, uintptr_t); - void *t12; - uint8_t *const *t16; - nav__4229_52 t17; - nav__4229_39 t18; - bool t3; - uint8_t t6; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = a1; - t3 = t2 == UINT64_C(0); - if (t3) { - return (nav__4229_39){(uint8_t *)(uintptr_t)0xfffffffffffffff8ul,0}; - } - goto zig_block_0; - - zig_block_0:; - t5 = (*t1); - t6 = mem_Alignment_fromByteUnits__1046((uintptr_t)8ul); - t7 = t5; - t1 = (struct mem_Allocator__565 const *)&t7; - t8 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t9 = (*t8); - t10 = (uint8_t *(*const *)(void *, uintptr_t, uint8_t, uintptr_t))&t9->alloc; - t11 = (*t10); - t12 = t5.ptr; - t13 = t11(t12, a1, t6, a2); - t3 = t13 != NULL; - if (t3) { - t14 = t13; - t4 = t14; - goto zig_block_1; - } - return (nav__4229_39){((uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),zig_error_OutOfMemory}; - - zig_block_1:; - t15 = t4; - t16 = (uint8_t *const *)&t15; - t14 = (*t16); - t14 = (uint8_t *)(((uintptr_t)t14) + ((uintptr_t)0ul*sizeof(uint8_t))); - t17.ptr = t14; - t17.len = a1; - t14 = (uint8_t *)t4; - t18.payload = t14; - t18.error = UINT16_C(0); - return t18; -} - -static bool fs_path_isAbsolute__4264(nav__4264_39 const a0) { - bool t0; - t0 = fs_path_isAbsolutePosix__4270(a0); - return t0; -} - -static struct fs_Dir__1860 fs_cwd__1134(void) { - struct fs_Dir__1860 t0; - t0 = (struct fs_Dir__1860){-INT32_C(100)}; - return t0; -} - -static uint16_t fs_Dir_access__3783(struct fs_Dir__1860 const a0, nav__3783_40 const a1, struct fs_File_OpenFlags__1858 const a2) { - struct fs_Dir__1860 const *t1; - uint8_t const (*t6)[4096]; - uint8_t const *t8; - struct fs_Dir__1860 t7; - struct fs_Dir__1860 t0; - nav__3783_49 t2; - uint16_t t3; - uint8_t t4[4096]; - uint8_t t5[4096]; - t0 = a0; - t1 = (struct fs_Dir__1860 const *)&t0; - t2 = posix_toPosixPath__1717(a1); - if (t2.error) { - t3 = t2.error; - return t3; - } - memcpy(t4, t2.payload, sizeof(uint8_t[4096])); - memcpy((char *)&t5, t4, sizeof(uint8_t[4096])); - t6 = (uint8_t const (*)[4096])&t5; - t7 = (*t1); - t8 = (uint8_t const *)t6; - t3 = fs_Dir_accessZ__3784(t7, t8, a2); - return t3; -} - -static nav__3719_39 fs_Dir_openFile__3719(struct fs_Dir__1860 const a0, nav__3719_42 const a1, struct fs_File_OpenFlags__1858 const a2) { - struct fs_Dir__1860 const *t1; - uint8_t const (*t8)[4096]; - uint8_t const *t10; - nav__3719_39 t5; - struct fs_Dir__1860 t9; - struct fs_Dir__1860 t0; - nav__3719_53 t3; - uint16_t t4; - uint8_t t6[4096]; - uint8_t t7[4096]; - struct fs_File_OpenFlags__1858 t2; - t0 = a0; - t1 = (struct fs_Dir__1860 const *)&t0; - t2 = a2; - t3 = posix_toPosixPath__1717(a1); - if (t3.error) { - t4 = t3.error; - t5.payload = (struct fs_File__608){-INT32_C(0x55555556)}; - t5.error = t4; - return t5; - } - memcpy(t6, t3.payload, sizeof(uint8_t[4096])); - memcpy((char *)&t7, t6, sizeof(uint8_t[4096])); - t8 = (uint8_t const (*)[4096])&t7; - t9 = (*t1); - t10 = (uint8_t const *)t8; - t5 = fs_Dir_openFileZ__3720(t9, t10, a2); - return t5; -} - -static uint16_t bincode_serializeUnion__anon_2860__5247(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__1946 const a1) { - struct shared_Command__struct_1949__1949 t4; - struct shared_Command__struct_1950__1950 t5; - struct shared_Command__struct_1951__1951 t6; - uint64_t t7; - uint32_t t1; - uint16_t t2; - uint8_t t0; - bool t3; - t0 = a1.tag; - t1 = (uint32_t)t0; - t2 = bincode_serialize__anon_3275__6904(a0, t1); - if (t2) { - return t2; - } - t0 = a1.tag; - t3 = t0 == UINT8_C(0); - if (t3) { - t4 = a1.payload.ExecutedBenchmark; - t2 = bincode_serialize__anon_3277__6905(a0, t4); - if (t2) { - return t2; - } - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - t0 = a1.tag; - t3 = t0 == UINT8_C(1); - if (t3) { - t2 = bincode_serialize__anon_3279__6906(a0); - if (t2) { - return t2; - } - goto zig_block_1; - } - goto zig_block_1; - - zig_block_1:; - t0 = a1.tag; - t3 = t0 == UINT8_C(2); - if (t3) { - t2 = bincode_serialize__anon_3279__6906(a0); - if (t2) { - return t2; - } - goto zig_block_2; - } - goto zig_block_2; - - zig_block_2:; - t0 = a1.tag; - t3 = t0 == UINT8_C(3); - if (t3) { - t2 = bincode_serialize__anon_3279__6906(a0); - if (t2) { - return t2; - } - goto zig_block_3; - } - goto zig_block_3; - - zig_block_3:; - t0 = a1.tag; - t3 = t0 == UINT8_C(4); - if (t3) { - t2 = bincode_serialize__anon_3279__6906(a0); - if (t2) { - return t2; - } - goto zig_block_4; - } - goto zig_block_4; - - zig_block_4:; - t0 = a1.tag; - t3 = t0 == UINT8_C(5); - if (t3) { - t5 = a1.payload.SetIntegration; - t2 = bincode_serialize__anon_3281__6907(a0, t5); - if (t2) { - return t2; - } - goto zig_block_5; - } - goto zig_block_5; - - zig_block_5:; - t0 = a1.tag; - t3 = t0 == UINT8_C(6); - if (t3) { - t2 = bincode_serialize__anon_3279__6906(a0); - if (t2) { - return t2; - } - goto zig_block_6; - } - goto zig_block_6; - - zig_block_6:; - t0 = a1.tag; - t3 = t0 == UINT8_C(7); - if (t3) { - t6 = a1.payload.AddMarker; - t2 = bincode_serialize__anon_3283__6908(a0, t6); - if (t2) { - return t2; - } - goto zig_block_7; - } - goto zig_block_7; - - zig_block_7:; - t0 = a1.tag; - t3 = t0 == UINT8_C(8); - if (t3) { - t7 = a1.payload.SetVersion; - t2 = bincode_serialize__anon_3285__6909(a0, t7); - if (t2) { - return t2; - } - goto zig_block_8; - } - goto zig_block_8; - - zig_block_8:; - return 0; -} - -static nav__3936_39 array_list_ArrayListAligned_28u8_2cnull_29_allocatedSlice__3936(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const a0) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const *t1; - nav__3936_39 const *t2; - uint8_t *const *t3; - uintptr_t t4; - uint8_t *t5; - nav__3936_39 t6; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t0; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 const *)&t0; - t2 = (nav__3936_39 const *)&t1->items; - t3 = &t2->ptr; - t4 = a0.capacity; - t5 = (*t3); - t5 = (uint8_t *)(((uintptr_t)t5) + ((uintptr_t)0ul*sizeof(uint8_t))); - t6.ptr = t5; - t6.len = t4; - return t6; -} - -static nav__1232_38 fs_File_write__1232(struct fs_File__608 const a0, nav__1232_41 const a1) { - nav__1232_38 t1; - int32_t t0; - t0 = a0.handle; - t1 = posix_write__1452(t0, a1); - return t1; -} - -static nav__1633_39 posix_clock_gettime__1633(uint32_t const a0) { - struct os_linux_timespec__struct_2922__2922 t3; - struct os_linux_timespec__struct_2922__2922 t0; - nav__1633_39 t4; - int t1; - uint16_t t2; - t1 = clock_gettime(a0, &t0); - t2 = posix_errno__anon_3451__6976(t1); - switch (t2) { - case UINT16_C(0): { - t3 = t0; - t4.payload = t3; - t4.error = UINT16_C(0); - return t4; - } - case UINT16_C(14): { - zig_unreachable(); - } - case UINT16_C(22): { - return (nav__1633_39){{-(intptr_t)0x5555555555555556,-(intptr_t)0x5555555555555556},zig_error_UnsupportedClock}; - } - default: { - t2 = posix_unexpectedErrno__1716(t2); - t4.payload = (struct os_linux_timespec__struct_2922__2922){-(intptr_t)0x5555555555555556,-(intptr_t)0x5555555555555556}; - t4.error = t2; - return t4; - } - } -} - -static nav__1222_38 fs_File_read__1222(struct fs_File__608 const a0, nav__1222_41 const a1) { - nav__1222_38 t1; - int32_t t0; - t0 = a0.handle; - t1 = posix_read__1444(t0, a1); - return t1; -} - -static nav__5248_39 mem_Allocator_allocWithSizeAndAlignment__anon_2953__5248(struct mem_Allocator__565 const a0, uintptr_t const a1, uintptr_t const a2) { - struct mem_Allocator__565 const *t1; - uintptr_t t2; - uintptr_t t5; - nav__5248_49 t3; - struct mem_Allocator__565 t6; - struct mem_Allocator__565 t0; - nav__5248_39 t7; - bool t4; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t3 = math_mul__anon_3472__6977((uintptr_t)1ul, a1); - t4 = t3.error == UINT16_C(0); - if (t4) { - t5 = t3.payload; - t2 = t5; - goto zig_block_0; - } - return (nav__5248_39){((uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),zig_error_OutOfMemory}; - - zig_block_0:; - t6 = (*t1); - t7 = mem_Allocator_allocBytesWithAlignment__anon_3474__6978(t6, t2, a2); - return t7; -} - -static nav__5249_39 mem_sliceAsBytes__anon_2966__5249(nav__5249_39 const a0) { - uintptr_t t0; - uint64_t t1; - uint8_t *t4; - uint8_t *t5; - uint8_t *const *t6; - nav__5249_39 t7; - bool t2; - bool t3; - t0 = a0.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - t3 = true; - goto zig_block_1; - } - t3 = false; - goto zig_block_1; - - zig_block_1:; - if (t3) { - return (nav__5249_39){(uint8_t *)((void const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),(uintptr_t)0ul}; - } - goto zig_block_0; - - zig_block_0:; - t4 = a0.ptr; - t5 = t4; - t6 = (uint8_t *const *)&t5; - t0 = a0.len; - t4 = (*t6); - t4 = (uint8_t *)(((uintptr_t)t4) + ((uintptr_t)0ul*sizeof(uint8_t))); - t7.ptr = t4; - t7.len = t0; - return t7; -} - -static uint8_t mem_Alignment_fromByteUnits__1046(uintptr_t const a0) { - bool t0; - uint8_t t1; - t0 = math_isPowerOfTwo__anon_3486__6979(a0); - debug_assert__180(t0); - t1 = zig_ctz_u64(a0, UINT8_C(64)); - return t1; -} - -static nav__4128_38 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_read__4128(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const a0, nav__4128_42 const a1) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t1; - nav__4128_42 const *t3; - uintptr_t t4; - uintptr_t t7; - uintptr_t t9; - nav__4128_42 *t5; - nav__4128_42 t6; - nav__4128_42 t13; - nav__4128_42 t2; - uintptr_t *t8; - uint64_t t10; - uint8_t *t11; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t12; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t0; - nav__4128_38 t14; - t0 = a0; - t1 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t0; - t2 = a1; - t3 = (nav__4128_42 const *)&t2; - t4 = a1.len; - t5 = (nav__4128_42 *)&a0->buffer; - t6 = (*t5); - t7 = t6.len; - t8 = (uintptr_t *)&a0->pos; - t9 = (*t8); - t9 = t7 - t9; - t9 = (t4 < t9) ? t4 : t9; - t10 = t9; - t8 = (uintptr_t *)&a0->pos; - t9 = (*t8); - t4 = t10; - t4 = t9 + t4; - t6 = (*t3); - t11 = t6.ptr; - t11 = (uint8_t *)(((uintptr_t)t11) + ((uintptr_t)0ul*sizeof(uint8_t))); - t9 = t10; - t6.ptr = t11; - t6.len = t9; - t12 = (*t1); - t5 = (nav__4128_42 *)&t12->buffer; - t8 = (uintptr_t *)&a0->pos; - t9 = (*t8); - t13 = (*t5); - t11 = t13.ptr; - t11 = (uint8_t *)(((uintptr_t)t11) + (t9*sizeof(uint8_t))); - t9 = t4 - t9; - t13.ptr = t11; - t13.len = t9; - t11 = t13.ptr; - if (t6.len != 0) memcpy(t6.ptr, t11, t6.len * sizeof(uint8_t)); - t12 = (*t1); - t8 = (uintptr_t *)&t12->pos; - (*t8) = t4; - t4 = t10; - t14.payload = t4; - t14.error = UINT16_C(0); - return t14; -} - -static uint16_t io_Reader_readNoEof__4178(struct io_Reader__2337 const a0, nav__4178_40 const a1) { - struct io_Reader__2337 const *t1; - struct io_Reader__2337 t2; - struct io_Reader__2337 t0; - nav__4178_43 t3; - uintptr_t t5; - uintptr_t t6; - uint64_t t7; - uint64_t t8; - uint16_t t4; - bool t9; - t0 = a0; - t1 = (struct io_Reader__2337 const *)&t0; - t2 = (*t1); - t3 = io_Reader_readAll__4176(t2, a1); - if (t3.error) { - t4 = t3.error; - return t4; - } - t5 = t3.payload; - t6 = a1.len; - t7 = t5; - t8 = t6; - t9 = t7 < t8; - if (t9) { - return zig_error_EndOfStream; - } - goto zig_block_0; - - zig_block_0:; - return 0; -} - -static nav__4177_38 io_Reader_readAtLeast__4177(struct io_Reader__2337 const a0, nav__4177_41 const a1, uintptr_t const a2) { - struct io_Reader__2337 const *t1; - nav__4177_41 const *t3; - uintptr_t t4; - uintptr_t t12; - uintptr_t t8; - uint64_t t5; - uint64_t t6; - struct io_Reader__2337 t9; - struct io_Reader__2337 t0; - nav__4177_41 t10; - nav__4177_41 t2; - uint8_t *t11; - nav__4177_38 t13; - uint16_t t14; - bool t7; - t0 = a0; - t1 = (struct io_Reader__2337 const *)&t0; - t2 = a1; - t3 = (nav__4177_41 const *)&t2; - t4 = a1.len; - t5 = a2; - t6 = t4; - t7 = t5 <= t6; - debug_assert__180(t7); - t8 = (uintptr_t)0ul; - zig_loop_17: - t4 = t8; - t6 = t4; - t5 = a2; - t7 = t6 < t5; - if (t7) { - t9 = (*t1); - t4 = t8; - t10 = (*t3); - t11 = t10.ptr; - t11 = (uint8_t *)(((uintptr_t)t11) + (t4*sizeof(uint8_t))); - t12 = t10.len; - t4 = t12 - t4; - t10.ptr = t11; - t10.len = t4; - t13 = io_Reader_read__4175(t9, t10); - if (t13.error) { - t14 = t13.error; - t13.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t13.error = t14; - return t13; - } - t4 = t13.payload; - t5 = t4; - t7 = t5 == UINT64_C(0); - if (t7) { - goto zig_block_0; - } - goto zig_block_2; - - zig_block_2:; - t12 = t8; - t4 = t12 + t4; - t8 = t4; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_17; - - zig_block_0:; - t12 = t8; - t13.payload = t12; - t13.error = UINT16_C(0); - return t13; -} - -static zig_cold zig_noreturn void debug_no_panic_call__5251(nav__5251_39 const a0, nav__5251_40 const a1) { - (void)a0; - (void)a1; - zig_trap(); -} - -static nav__6121_38 math_cast__anon_3113__6121(uint64_t const a0) { - long t1; - nav__6121_38 t2; - bool t0; - t0 = a0 > UINT64_C(9223372036854775807); - if (t0) { - return (nav__6121_38){-0x5555555555555556l,true}; - } - t1 = (long)a0; - t2.is_null = false; - t2.payload = t1; - return t2; -} - -static void mem_Allocator_free__anon_3185__6890(struct mem_Allocator__565 const a0, nav__6890_40 const a1) { - struct mem_Allocator__565 const *t1; - nav__6890_40 t2; - uintptr_t t3; - uint64_t t4; - uint8_t const *t6; - uint8_t *t7; - uint8_t *t8; - uint8_t *const *t9; - nav__6890_51 t10; - struct mem_Allocator__565 t11; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t13; - struct mem_Allocator_VTable__568 const *const *t14; - struct mem_Allocator_VTable__568 const *t15; - void (*const *t16)(void *, nav__6890_51, uint8_t, uintptr_t); - void (*t17)(void *, nav__6890_51, uint8_t, uintptr_t); - void *t18; - bool t5; - uint8_t t12; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = mem_sliceAsBytes__anon_3508__6980(a1); - t3 = t2.len; - t4 = t3; - t5 = t4 == UINT64_C(0); - if (t5) { - return; - } - goto zig_block_0; - - zig_block_0:; - t6 = t2.ptr; - t7 = (uint8_t *)t6; - t8 = t7; - t9 = (uint8_t *const *)&t8; - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t10.ptr = t7; - t10.len = t3; - t11 = (*t1); - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t10.ptr = t7; - t10.len = t3; - t12 = mem_Alignment_fromByteUnits__1046((uintptr_t)1ul); - t3 = (uintptr_t)zig_return_address(); - t13 = t11; - t1 = (struct mem_Allocator__565 const *)&t13; - t14 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t15 = (*t14); - t16 = (void (*const *)(void *, nav__6890_51, uint8_t, uintptr_t))&t15->free; - t17 = (*t16); - t18 = t11.ptr; - t17(t18, t10, t12, t3); - return; -} - -static void fifo_UnixPipe_Writer_deinit__1081(struct fifo_UnixPipe_Writer__600 *const a0) { - struct fifo_UnixPipe_Writer__600 *const *t1; - struct fifo_UnixPipe_Writer__600 *t2; - struct fifo_UnixPipe_Writer__600 *t0; - struct fs_File__608 *t3; - struct fs_File__608 t4; - t0 = a0; - t1 = (struct fifo_UnixPipe_Writer__600 *const *)&t0; - t2 = (*t1); - t3 = (struct fs_File__608 *)&t2->file; - t4 = (*t3); - fs_File_close__1179(t4); - return; -} - -static void fifo_UnixPipe_Reader_deinit__1088(struct fifo_UnixPipe_Reader__602 *const a0) { - struct fifo_UnixPipe_Reader__602 *const *t1; - struct fifo_UnixPipe_Reader__602 *t2; - struct fifo_UnixPipe_Reader__602 *t0; - struct fs_File__608 *t3; - struct fs_File__608 t4; - t0 = a0; - t1 = (struct fifo_UnixPipe_Reader__602 *const *)&t0; - t2 = (*t1); - t3 = (struct fs_File__608 *)&t2->file; - t4 = (*t3); - fs_File_close__1179(t4); - return; -} - -static bool fs_path_isAbsolutePosix__4270(nav__4270_39 const a0) { - uintptr_t t0; - uint64_t t1; - bool t2; - bool t3; - uint8_t t4; - t0 = a0.len; - t1 = t0; - t2 = t1 > UINT64_C(0); - if (t2) { - t4 = a0.ptr[(uintptr_t)0ul]; - t2 = t4 == UINT8_C(47); - t3 = t2; - goto zig_block_0; - } - t3 = false; - goto zig_block_0; - - zig_block_0:; - return t3; -} - -static nav__1717_39 posix_toPosixPath__1717(nav__1717_41 const a0) { - uintptr_t t1; - uint64_t t2; - uint8_t *t4; - nav__1717_47 t5; - uint8_t const *t6; - nav__1717_39 t8; - bool t3; - uint8_t t7[4096]; - uint8_t t0[4096]; - t1 = a0.len; - t2 = t1; - t3 = t2 >= UINT64_C(4096); - if (t3) { - return (nav__1717_39){zig_error_NameTooLong,{'\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa','\xaa'}}; - } - goto zig_block_0; - - zig_block_0:; - t1 = a0.len; - t4 = (uint8_t *)&t0; - t4 = (uint8_t *)(((uintptr_t)t4) + ((uintptr_t)0ul*sizeof(uint8_t))); - t5.ptr = t4; - t5.len = t1; - t6 = a0.ptr; - if (t5.len != 0) memcpy(t5.ptr, t6, t5.len * sizeof(uint8_t)); - t1 = a0.len; - t4 = (uint8_t *)&t0[t1]; - (*t4) = UINT8_C(0); - memcpy(t7, (const char *)&t0, sizeof(uint8_t[4096])); - memcpy(t8.payload, t7, sizeof(uint8_t[4096])); - t8.error = UINT16_C(0); - return t8; -} - -static uint16_t fs_Dir_accessZ__3784(struct fs_Dir__1860 const a0, uint8_t const *const a1, struct fs_File_OpenFlags__1858 const a2) { - uint32_t t2; - int32_t t3; - struct fs_Dir__1860 t0; - uint16_t t4; - uint8_t t1; - t0 = a0; - t1 = a2.mode; - switch (t1) { - case UINT8_C(0): { - t2 = UINT32_C(0); - goto zig_block_0; - } - case UINT8_C(1): { - t2 = UINT32_C(2); - goto zig_block_0; - } - case UINT8_C(2): { - t2 = UINT32_C(6); - goto zig_block_0; - } - default: zig_unreachable(); - } - - zig_block_0:; - t3 = a0.fd; - t4 = posix_faccessatZ__1608(t3, a1, t2, UINT32_C(0)); - return t4; -} - -static nav__3720_39 fs_Dir_openFileZ__3720(struct fs_Dir__1860 const a0, uint8_t const *const a1, struct fs_File_OpenFlags__1858 const a2) { - uint32_t *t2; - struct fs_File__608 *t14; - int32_t *t15; - int32_t t6; - int32_t t11; - int32_t t12; - uint32_t t7; - uint32_t t1; - nav__3720_50 t8; - nav__3720_39 t10; - nav__3720_39 t13; - struct fs_Dir__1860 t0; - uint16_t t9; - uint8_t t3; - uint8_t t4; - bool t5; - t0 = a0; - t2 = (uint32_t *)&t1; - t3 = a2.mode; - switch (t3) { - case UINT8_C(0): { - t4 = UINT8_C(0); - goto zig_block_0; - } - case UINT8_C(1): { - t4 = UINT8_C(1); - goto zig_block_0; - } - case UINT8_C(2): { - t4 = UINT8_C(2); - goto zig_block_0; - } - default: zig_unreachable(); - } - - zig_block_0:; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffffffc)), zig_shl_u32((uint32_t)t4, UINT8_C(0))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffffc3)), zig_shl_u32((uint32_t)UINT8_C(0), UINT8_C(2))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffffbf)), zig_shl_u32((uint32_t)false, UINT8_C(6))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffff7f)), zig_shl_u32((uint32_t)false, UINT8_C(7))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffffeff)), zig_shl_u32((uint32_t)false, UINT8_C(8))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffffdff)), zig_shl_u32((uint32_t)false, UINT8_C(9))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffffbff)), zig_shl_u32((uint32_t)false, UINT8_C(10))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffff7ff)), zig_shl_u32((uint32_t)false, UINT8_C(11))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffefff)), zig_shl_u32((uint32_t)false, UINT8_C(12))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffdfff)), zig_shl_u32((uint32_t)false, UINT8_C(13))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffffbfff)), zig_shl_u32((uint32_t)false, UINT8_C(14))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffff7fff)), zig_shl_u32((uint32_t)UINT8_C(0), UINT8_C(15))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffeffff)), zig_shl_u32((uint32_t)false, UINT8_C(16))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffdffff)), zig_shl_u32((uint32_t)false, UINT8_C(17))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffbffff)), zig_shl_u32((uint32_t)false, UINT8_C(18))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfff7ffff)), zig_shl_u32((uint32_t)false, UINT8_C(19))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffefffff)), zig_shl_u32((uint32_t)false, UINT8_C(20))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffdfffff)), zig_shl_u32((uint32_t)false, UINT8_C(21))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xffbfffff)), zig_shl_u32((uint32_t)false, UINT8_C(22))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0x7fffff)), zig_shl_u32((uint32_t)UINT16_C(0), UINT8_C(23))); - t2 = (uint32_t *)&t1; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfff7ffff)), zig_shl_u32((uint32_t)true, UINT8_C(19))); - t2 = (uint32_t *)&t1; - t5 = a2.allow_ctty; - t5 = !t5; - (*t2) = zig_or_u32(zig_and_u32((*t2), UINT32_C(0xfffffeff)), zig_shl_u32((uint32_t)t5, UINT8_C(8))); - t6 = a0.fd; - t7 = t1; - t8 = posix_openatZ__1464(t6, a1, t7, (uintptr_t)0ul); - if (t8.error) { - t9 = t8.error; - t10.payload = (struct fs_File__608){-INT32_C(0x55555556)}; - t10.error = t9; - return t10; - } - t6 = t8.payload; - t4 = a2.lock; - t5 = t4 != UINT8_C(0); - if (t5) { - t5 = a2.lock_nonblocking; - if (t5) { - t11 = INT32_C(4); - goto zig_block_2; - } - t11 = INT32_C(0); - goto zig_block_2; - - zig_block_2:; - t4 = a2.lock; - switch (t4) { - case UINT8_C(0): { - zig_unreachable(); - } - case UINT8_C(1): { - t11 = INT32_C(1) | t11; - t12 = t11; - goto zig_block_3; - } - case UINT8_C(2): { - t11 = INT32_C(2) | t11; - t12 = t11; - goto zig_block_3; - } - default: zig_unreachable(); - } - - zig_block_3:; - t9 = posix_flock__1625(t6, t12); - if (t9) { - posix_close__1422(t6); - t10.payload = (struct fs_File__608){-INT32_C(0x55555556)}; - t10.error = t9; - return t10; - } - goto zig_block_1; - } - goto zig_block_1; - - zig_block_1:; - t13.error = UINT16_C(0); - t14 = &t13.payload; - t15 = (int32_t *)&t14->handle; - (*t15) = t6; - return t13; -} - -static uint16_t bincode_serialize__anon_3275__6904(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, uint32_t const a1) { - uint16_t t0; - t0 = bincode_serializeInt__anon_3646__7041(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static uint16_t bincode_serialize__anon_3277__6905(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1949__1949 const a1) { - uint16_t t0; - t0 = bincode_serializeStruct__anon_3651__7042(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static uint16_t bincode_serialize__anon_3279__6906(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0) { - (void)a0; - return 0; -} - -static uint16_t bincode_serialize__anon_3281__6907(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1950__1950 const a1) { - uint16_t t0; - t0 = bincode_serializeStruct__anon_3652__7043(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static uint16_t bincode_serialize__anon_3283__6908(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1951__1951 const a1) { - uint16_t t0; - t0 = bincode_serializeStruct__anon_3653__7044(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static uint16_t bincode_serialize__anon_3285__6909(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, uint64_t const a1) { - uint16_t t0; - t0 = bincode_serializeInt__anon_3654__7045(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static nav__1452_38 posix_write__1452(int32_t const a0, nav__1452_40 const a1) { - uintptr_t t0; - uint64_t t1; - uint8_t const *t3; - intptr_t t5; - nav__1452_38 t7; - uint32_t t4; - uint16_t t6; - bool t2; - t0 = a1.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - return (nav__1452_38){(uintptr_t)0ul,0}; - } - goto zig_block_0; - - zig_block_0:; - zig_loop_16: - t3 = a1.ptr; - t0 = a1.len; - t0 = ((uintptr_t)2147479552ul < t0) ? (uintptr_t)2147479552ul : t0; - t4 = (uint32_t)t0; - t0 = (uintptr_t)t4; - t5 = write(a0, t3, t0); - t6 = posix_errno__anon_3665__7047(t5); - switch (t6) { - case UINT16_C(0): { - t0 = (uintptr_t)t5; - t7.payload = t0; - t7.error = UINT16_C(0); - return t7; - } - case UINT16_C(4): { - goto zig_block_1; - } - case UINT16_C(22): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_InvalidArgument}; - } - case UINT16_C(14): { - zig_unreachable(); - } - case UINT16_C(2): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_ProcessNotFound}; - } - case UINT16_C(11): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_WouldBlock}; - } - case UINT16_C(9): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NotOpenForWriting}; - } - case UINT16_C(89): { - zig_unreachable(); - } - case UINT16_C(122): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_DiskQuota}; - } - case UINT16_C(27): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_FileTooBig}; - } - case UINT16_C(5): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_InputOutput}; - } - case UINT16_C(28): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NoSpaceLeft}; - } - case UINT16_C(13): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_AccessDenied}; - } - case UINT16_C(1): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_AccessDenied}; - } - case UINT16_C(32): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_BrokenPipe}; - } - case UINT16_C(104): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_ConnectionResetByPeer}; - } - case UINT16_C(16): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_DeviceBusy}; - } - case UINT16_C(6): { - return (nav__1452_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NoDevice}; - } - default: { - t6 = posix_unexpectedErrno__1716(t6); - t7.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t7.error = t6; - return t7; - } - } - - zig_block_1:; - goto zig_loop_16; -} - -static uint16_t posix_errno__anon_3451__6976(int const a0) { - int *t3; - int32_t t1; - int t4; - uint16_t t0; - uint16_t t5; - bool t2; - t1 = a0; - t2 = t1 == -INT32_C(1); - if (t2) { - t3 = zig_e___errno_location(); - t4 = (*t3); - t5 = (uint16_t)t4; - t0 = t5; - goto zig_block_0; - } - t0 = UINT16_C(0); - goto zig_block_0; - - zig_block_0:; - return t0; -} - -static uint16_t posix_unexpectedErrno__1716(uint16_t const a0) { - (void)a0; - return zig_error_Unexpected; -} - -static nav__1444_38 posix_read__1444(int32_t const a0, nav__1444_40 const a1) { - uintptr_t t0; - uint64_t t1; - uint8_t *t3; - intptr_t t5; - nav__1444_38 t7; - uint32_t t4; - uint16_t t6; - bool t2; - t0 = a1.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - return (nav__1444_38){(uintptr_t)0ul,0}; - } - goto zig_block_0; - - zig_block_0:; - zig_loop_16: - t3 = a1.ptr; - t0 = a1.len; - t0 = ((uintptr_t)2147479552ul < t0) ? (uintptr_t)2147479552ul : t0; - t4 = (uint32_t)t0; - t0 = (uintptr_t)t4; - t5 = read(a0, t3, t0); - t6 = posix_errno__anon_3665__7047(t5); - switch (t6) { - case UINT16_C(0): { - t0 = (uintptr_t)t5; - t7.payload = t0; - t7.error = UINT16_C(0); - return t7; - } - case UINT16_C(4): { - goto zig_block_1; - } - case UINT16_C(22): { - zig_unreachable(); - } - case UINT16_C(14): { - zig_unreachable(); - } - case UINT16_C(2): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_ProcessNotFound}; - } - case UINT16_C(11): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_WouldBlock}; - } - case UINT16_C(125): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_Canceled}; - } - case UINT16_C(9): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NotOpenForReading}; - } - case UINT16_C(5): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_InputOutput}; - } - case UINT16_C(21): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_IsDir}; - } - case UINT16_C(105): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_SystemResources}; - } - case UINT16_C(12): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_SystemResources}; - } - case UINT16_C(107): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_SocketNotConnected}; - } - case UINT16_C(104): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_ConnectionResetByPeer}; - } - case UINT16_C(110): { - return (nav__1444_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_ConnectionTimedOut}; - } - default: { - t6 = posix_unexpectedErrno__1716(t6); - t7.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t7.error = t6; - return t7; - } - } - - zig_block_1:; - goto zig_loop_16; -} - -static nav__6977_38 math_mul__anon_3472__6977(uintptr_t const a0, uintptr_t const a1) { - nav__6977_42 t0; - uintptr_t t3; - nav__6977_38 t4; - uint8_t t1; - bool t2; - t0.f1 = zig_mulo_u64(&t0.f0, a0, a1, UINT8_C(64)); - t1 = t0.f1; - t2 = t1 != UINT8_C(0); - if (t2) { - return (nav__6977_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_Overflow}; - } - goto zig_block_0; - - zig_block_0:; - t3 = t0.f0; - t4.payload = t3; - t4.error = UINT16_C(0); - return t4; -} - -static nav__6978_39 mem_Allocator_allocBytesWithAlignment__anon_3474__6978(struct mem_Allocator__565 const a0, uintptr_t const a1, uintptr_t const a2) { - struct mem_Allocator__565 const *t1; - uint64_t t2; - uint8_t *t4; - uint8_t *t13; - uint8_t *t14; - uint8_t *t15; - struct mem_Allocator__565 t5; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t7; - struct mem_Allocator_VTable__568 const *const *t8; - struct mem_Allocator_VTable__568 const *t9; - uint8_t *(*const *t10)(void *, uintptr_t, uint8_t, uintptr_t); - uint8_t *(*t11)(void *, uintptr_t, uint8_t, uintptr_t); - void *t12; - uint8_t *const *t16; - nav__6978_52 t17; - nav__6978_39 t18; - bool t3; - uint8_t t6; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = a1; - t3 = t2 == UINT64_C(0); - if (t3) { - return (nav__6978_39){(uint8_t *)UINTPTR_MAX,0}; - } - goto zig_block_0; - - zig_block_0:; - t5 = (*t1); - t6 = mem_Alignment_fromByteUnits__1046((uintptr_t)1ul); - t7 = t5; - t1 = (struct mem_Allocator__565 const *)&t7; - t8 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t9 = (*t8); - t10 = (uint8_t *(*const *)(void *, uintptr_t, uint8_t, uintptr_t))&t9->alloc; - t11 = (*t10); - t12 = t5.ptr; - t13 = t11(t12, a1, t6, a2); - t3 = t13 != NULL; - if (t3) { - t14 = t13; - t4 = t14; - goto zig_block_1; - } - return (nav__6978_39){((uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),zig_error_OutOfMemory}; - - zig_block_1:; - t15 = t4; - t16 = (uint8_t *const *)&t15; - t14 = (*t16); - t14 = (uint8_t *)(((uintptr_t)t14) + ((uintptr_t)0ul*sizeof(uint8_t))); - t17.ptr = t14; - t17.len = a1; - t18.payload = t4; - t18.error = UINT16_C(0); - return t18; -} - -static bool math_isPowerOfTwo__anon_3486__6979(uintptr_t const a0) { - uint64_t t0; - uintptr_t t2; - bool t1; - t0 = a0; - t1 = t0 > UINT64_C(0); - debug_assert__180(t1); - t2 = a0 - (uintptr_t)1ul; - t2 = a0 & t2; - t0 = t2; - t1 = t0 == UINT64_C(0); - return t1; -} - -static nav__4175_38 io_Reader_read__4175(struct io_Reader__2337 const a0, nav__4175_41 const a1) { - struct io_Reader__2337 const *t1; - nav__4175_38 (*const *t2)(void const *, nav__4175_41); - nav__4175_38 (*t3)(void const *, nav__4175_41); - void const *t4; - nav__4175_38 t5; - struct io_Reader__2337 t0; - t0 = a0; - t1 = (struct io_Reader__2337 const *)&t0; - t2 = (nav__4175_38 (*const *)(void const *, nav__4175_41))&t1->readFn; - t3 = (*t2); - t4 = a0.context; - t5 = t3(t4, a1); - return t5; -} - -static nav__6980_39 mem_sliceAsBytes__anon_3508__6980(nav__6980_39 const a0) { - uintptr_t t0; - uint64_t t1; - uint8_t const *t4; - uint8_t const *t5; - uint8_t const *const *t6; - nav__6980_39 t7; - bool t2; - bool t3; - t0 = a0.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - t3 = true; - goto zig_block_1; - } - t3 = false; - goto zig_block_1; - - zig_block_1:; - if (t3) { - return (nav__6980_39){(uint8_t const *)((void const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),(uintptr_t)0ul}; - } - goto zig_block_0; - - zig_block_0:; - t4 = a0.ptr; - t5 = t4; - t6 = (uint8_t const *const *)&t5; - t0 = a0.len; - t4 = (*t6); - t4 = (uint8_t const *)(((uintptr_t)t4) + ((uintptr_t)0ul*sizeof(uint8_t))); - t7.ptr = t4; - t7.len = t0; - return t7; -} - -static void fs_File_close__1179(struct fs_File__608 const a0) { - int32_t t0; - t0 = a0.handle; - posix_close__1422(t0); - return; -} - -static uint16_t posix_faccessatZ__1608(int32_t const a0, uint8_t const *const a1, uint32_t const a2, uint32_t const a3) { - unsigned int t0; - unsigned int t1; - int t2; - uint16_t t3; - t0 = a2; - t1 = a3; - t2 = faccessat(a0, a1, t0, t1); - t3 = posix_errno__anon_3451__6976(t2); - switch (t3) { - case UINT16_C(0): { - return 0; - } - case UINT16_C(13): { - return zig_error_PermissionDenied; - } - case UINT16_C(1): { - return zig_error_PermissionDenied; - } - case UINT16_C(30): { - return zig_error_ReadOnlyFileSystem; - } - case UINT16_C(40): { - return zig_error_SymLinkLoop; - } - case UINT16_C(26): { - return zig_error_FileBusy; - } - case UINT16_C(20): { - return zig_error_FileNotFound; - } - case UINT16_C(2): { - return zig_error_FileNotFound; - } - case UINT16_C(36): { - return zig_error_NameTooLong; - } - case UINT16_C(22): { - zig_unreachable(); - } - case UINT16_C(14): { - zig_unreachable(); - } - case UINT16_C(5): { - return zig_error_InputOutput; - } - case UINT16_C(12): { - return zig_error_SystemResources; - } - case UINT16_C(84): { - t3 = posix_unexpectedErrno__1716(t3); - return t3; - } - default: { - t3 = posix_unexpectedErrno__1716(t3); - return t3; - } - } -} - -static nav__1464_38 posix_openatZ__1464(int32_t const a0, uint8_t const *const a1, uint32_t const a2, uintptr_t const a3) { - unsigned long t1; - int t0; - int32_t t3; - nav__1464_38 t4; - uint16_t t2; - zig_loop_11: - t0 = a0; - t1 = a3; - t0 = openat64(t0, a1, a2, t1); - t2 = posix_errno__anon_3451__6976(t0); - switch (t2) { - case UINT16_C(0): { - t3 = t0; - t4.payload = t3; - t4.error = UINT16_C(0); - return t4; - } - case UINT16_C(4): { - goto zig_block_0; - } - case UINT16_C(14): { - zig_unreachable(); - } - case UINT16_C(22): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_BadPathName}; - } - case UINT16_C(9): { - zig_unreachable(); - } - case UINT16_C(13): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_AccessDenied}; - } - case UINT16_C(27): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_FileTooBig}; - } - case UINT16_C(75): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_FileTooBig}; - } - case UINT16_C(21): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_IsDir}; - } - case UINT16_C(40): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_SymLinkLoop}; - } - case UINT16_C(24): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_ProcessFdQuotaExceeded}; - } - case UINT16_C(36): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_NameTooLong}; - } - case UINT16_C(23): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_SystemFdQuotaExceeded}; - } - case UINT16_C(19): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_NoDevice}; - } - case UINT16_C(2): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_FileNotFound}; - } - case UINT16_C(12): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_SystemResources}; - } - case UINT16_C(28): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_NoSpaceLeft}; - } - case UINT16_C(20): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_NotDir}; - } - case UINT16_C(1): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_AccessDenied}; - } - case UINT16_C(17): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_PathAlreadyExists}; - } - case UINT16_C(16): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_DeviceBusy}; - } - case UINT16_C(95): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_FileLocksNotSupported}; - } - case UINT16_C(11): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_WouldBlock}; - } - case UINT16_C(26): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_FileBusy}; - } - case UINT16_C(6): { - return (nav__1464_38){-INT32_C(0x55555556),zig_error_NoDevice}; - } - case UINT16_C(84): { - t2 = posix_unexpectedErrno__1716(t2); - t4.payload = -INT32_C(0x55555556); - t4.error = t2; - return t4; - } - default: { - t2 = posix_unexpectedErrno__1716(t2); - t4.payload = -INT32_C(0x55555556); - t4.error = t2; - return t4; - } - } - - zig_block_0:; - goto zig_loop_11; -} - -static uint16_t posix_flock__1625(int32_t const a0, int32_t const a1) { - int t0; - uint16_t t1; - zig_loop_3: - t0 = a1; - t0 = flock(a0, t0); - t1 = posix_errno__anon_3451__6976(t0); - switch (t1) { - case UINT16_C(0): { - return 0; - } - case UINT16_C(9): { - zig_unreachable(); - } - case UINT16_C(4): { - goto zig_block_0; - } - case UINT16_C(22): { - zig_unreachable(); - } - case UINT16_C(37): { - return zig_error_SystemResources; - } - case UINT16_C(11): { - return zig_error_WouldBlock; - } - case UINT16_C(95): { - return zig_error_FileLocksNotSupported; - } - default: { - t1 = posix_unexpectedErrno__1716(t1); - return t1; - } - } - - zig_block_0:; - goto zig_loop_3; -} - -static void posix_close__1422(int32_t const a0) { - int t0; - uint16_t t1; - t0 = close(a0); - t1 = posix_errno__anon_3451__6976(t0); - switch (t1) { - case UINT16_C(9): { - zig_unreachable(); - } - case UINT16_C(4): { - return; - } - default: { - return; - } - } -} - -static uint16_t bincode_serializeInt__anon_3646__7041(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, uint32_t const a1) { - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t1; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t4; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t2; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t0; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t3; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *t5; - void const **t7; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t8; - void const *t9; - nav__7041_48 (**t10)(void const *, nav__7041_50); - struct io_Writer__3920 t11; - struct io_Writer__3920 t6; - struct io_Writer__3920 t12; - struct io_Writer__3920 t14; - struct io_Writer__3920 const *t13; - nav__7041_50 t17; - uint16_t t18; - uint16_t t19; - uint8_t t16[4]; - uint8_t t15[4]; - t0 = a0; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t0; - t2 = (*t1); - t3 = t2; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t3; - t4 = t1; - t5 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *)&t4; - t7 = (void const **)&t6.context; - t1 = (*t5); - t8 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t1->context; - t9 = (void const *)t8; - (*t7) = t9; - t10 = (nav__7041_48 (**)(void const *, nav__7041_50))&t6.writeFn; - (*t10) = &io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060; - t11 = t6; - t12 = t11; - t13 = (struct io_Writer__3920 const *)&t12; - t11 = (*t13); - t14 = t11; - t13 = (struct io_Writer__3920 const *)&t14; - memcpy(&t16, &a1, sizeof(uint8_t[4])); - memcpy((char *)&t15, t16, sizeof(uint8_t[4])); - t11 = (*t13); - t17.ptr = &t15[(uintptr_t)0ul]; - t17.len = (uintptr_t)4ul; - t18 = io_Writer_writeAll__7060(t11, t17); - memcpy(&t19, &t18, sizeof(uint16_t)); - if (t19) { - return t19; - } - return 0; -} - -static uint16_t bincode_serializeStruct__anon_3651__7042(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1949__1949 const a1) { - nav__7042_45 t2; - uint32_t t0; - uint16_t t1; - t0 = a1.pid; - t1 = bincode_serialize__anon_3275__6904(a0, t0); - if (t1) { - return t1; - } - t2 = a1.uri; - t1 = bincode_serialize__anon_3956__7069(a0, t2); - if (t1) { - return t1; - } - return 0; -} - -static uint16_t bincode_serializeStruct__anon_3652__7043(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1950__1950 const a1) { - nav__7043_45 t0; - uint16_t t1; - t0 = a1.name; - t1 = bincode_serialize__anon_3956__7069(a0, t0); - if (t1) { - return t1; - } - t0 = a1.version; - t1 = bincode_serialize__anon_3956__7069(a0, t0); - if (t1) { - return t1; - } - return 0; -} - -static uint16_t bincode_serializeStruct__anon_3653__7044(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_Command__struct_1951__1951 const a1) { - struct shared_MarkerType__1953 t2; - uint32_t t0; - uint16_t t1; - t0 = a1.pid; - t1 = bincode_serialize__anon_3275__6904(a0, t0); - if (t1) { - return t1; - } - t2 = a1.marker; - t1 = bincode_serialize__anon_3958__7070(a0, t2); - if (t1) { - return t1; - } - return 0; -} - -static uint16_t bincode_serializeInt__anon_3654__7045(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, uint64_t const a1) { - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t1; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t4; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t2; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t0; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t3; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *t5; - void const **t7; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t8; - void const *t9; - nav__7045_48 (**t10)(void const *, nav__7045_50); - struct io_Writer__3920 t11; - struct io_Writer__3920 t6; - struct io_Writer__3920 t12; - struct io_Writer__3920 t14; - struct io_Writer__3920 const *t13; - nav__7045_50 t17; - uint16_t t18; - uint16_t t19; - uint8_t t16[8]; - uint8_t t15[8]; - t0 = a0; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t0; - t2 = (*t1); - t3 = t2; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t3; - t4 = t1; - t5 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *)&t4; - t7 = (void const **)&t6.context; - t1 = (*t5); - t8 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t1->context; - t9 = (void const *)t8; - (*t7) = t9; - t10 = (nav__7045_48 (**)(void const *, nav__7045_50))&t6.writeFn; - (*t10) = &io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060; - t11 = t6; - t12 = t11; - t13 = (struct io_Writer__3920 const *)&t12; - t11 = (*t13); - t14 = t11; - t13 = (struct io_Writer__3920 const *)&t14; - memcpy(&t16, &a1, sizeof(uint8_t[8])); - memcpy((char *)&t15, t16, sizeof(uint8_t[8])); - t11 = (*t13); - t17.ptr = &t15[(uintptr_t)0ul]; - t17.len = (uintptr_t)8ul; - t18 = io_Writer_writeAll__7060(t11, t17); - memcpy(&t19, &t18, sizeof(uint16_t)); - if (t19) { - return t19; - } - return 0; -} - -static uint16_t posix_errno__anon_3665__7047(intptr_t const a0) { - int64_t t1; - int *t3; - int t4; - uint16_t t0; - uint16_t t5; - bool t2; - t1 = a0; - t2 = t1 == -INT64_C(1); - if (t2) { - t3 = zig_e___errno_location(); - t4 = (*t3); - t5 = (uint16_t)t4; - t0 = t5; - goto zig_block_0; - } - t0 = UINT16_C(0); - goto zig_block_0; - - zig_block_0:; - return t0; -} - -static nav__4060_38 io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060(void const *const a0, nav__4060_41 const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t0; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t1; - nav__4060_38 t2; - nav__4060_38 t3; - t0 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)a0; - t1 = (*t0); - t2 = array_list_ArrayListAligned_28u8_2cnull_29_appendWrite__3914(t1, a1); - memcpy(&t3, &t2, sizeof(nav__4060_38)); - return t3; -} - -static uint16_t io_Writer_writeAll__7060(struct io_Writer__3920 const a0, nav__7060_40 const a1) { - struct io_Writer__3920 const *t1; - nav__7060_40 const *t3; - uintptr_t t5; - uintptr_t t6; - uintptr_t t13; - uintptr_t t4; - uint64_t t7; - uint64_t t8; - struct io_Writer__3920 t10; - struct io_Writer__3920 t0; - nav__7060_40 t11; - nav__7060_40 t2; - uint8_t const *t12; - nav__7060_43 t14; - uint16_t t15; - bool t9; - t0 = a0; - t1 = (struct io_Writer__3920 const *)&t0; - t2 = a1; - t3 = (nav__7060_40 const *)&t2; - t4 = (uintptr_t)0ul; - zig_loop_11: - t5 = t4; - t6 = a1.len; - t7 = t5; - t8 = t6; - t9 = t7 != t8; - if (t9) { - t6 = t4; - t10 = (*t1); - t5 = t4; - t11 = (*t3); - t12 = t11.ptr; - t12 = (uint8_t const *)(((uintptr_t)t12) + (t5*sizeof(uint8_t))); - t13 = t11.len; - t5 = t13 - t5; - t11.ptr = t12; - t11.len = t5; - t14 = io_Writer_write__7059(t10, t11); - if (t14.error) { - t15 = t14.error; - return t15; - } - t5 = t14.payload; - t5 = t6 + t5; - t4 = t5; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_11; - - zig_block_0:; - return 0; -} - -static uint16_t bincode_serialize__anon_3956__7069(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, nav__7069_40 const a1) { - uint16_t t0; - t0 = bincode_serializePointer__anon_3971__7071(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static uint16_t bincode_serialize__anon_3958__7070(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_MarkerType__1953 const a1) { - uint16_t t0; - t0 = bincode_serializeUnion__anon_3972__7072(a0, a1); - if (t0) { - return t0; - } - return 0; -} - -static nav__3914_38 array_list_ArrayListAligned_28u8_2cnull_29_appendWrite__3914(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, nav__3914_42 const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t2; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - nav__3914_38 t4; - uintptr_t t5; - uint16_t t3; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (*t1); - t3 = array_list_ArrayListAligned_28u8_2cnull_29_appendSlice__3908(t2, a1); - if (t3) { - t4.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t4.error = t3; - return t4; - } - t5 = a1.len; - t4.payload = t5; - t4.error = UINT16_C(0); - return t4; -} - -static nav__7059_38 io_Writer_write__7059(struct io_Writer__3920 const a0, nav__7059_41 const a1) { - struct io_Writer__3920 const *t1; - nav__7059_38 (*const *t2)(void const *, nav__7059_41); - nav__7059_38 (*t3)(void const *, nav__7059_41); - void const *t4; - nav__7059_38 t5; - struct io_Writer__3920 t0; - t0 = a0; - t1 = (struct io_Writer__3920 const *)&t0; - t2 = (nav__7059_38 (*const *)(void const *, nav__7059_41))&t1->writeFn; - t3 = (*t2); - t4 = a0.context; - t5 = t3(t4, a1); - return t5; -} - -static uint16_t bincode_serializePointer__anon_3971__7071(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, nav__7071_40 const a1) { - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t1; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t6; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t7; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *t24; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t2; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t0; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t5; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 t23; - uintptr_t t3; - uint64_t t4; - struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *t8; - void const **t10; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t11; - void const *t12; - nav__7071_51 (**t13)(void const *, nav__7071_40); - struct io_Writer__3920 t14; - struct io_Writer__3920 t9; - struct io_Writer__3920 t15; - struct io_Writer__3920 t17; - struct io_Writer__3920 t25; - struct io_Writer__3920 t26; - struct io_Writer__3920 const *t16; - nav__7071_40 t20; - uint16_t t21; - uint16_t t22; - uint8_t t19[8]; - uint8_t t18[8]; - t0 = a0; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t0; - t2 = (*t1); - t3 = a1.len; - t4 = t3; - t5 = t2; - t6 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t5; - t7 = t6; - t8 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *)&t7; - t10 = (void const **)&t9.context; - t6 = (*t8); - t11 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t6->context; - t12 = (void const *)t11; - (*t10) = t12; - t13 = (nav__7071_51 (**)(void const *, nav__7071_40))&t9.writeFn; - (*t13) = &io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060; - t14 = t9; - t15 = t14; - t16 = (struct io_Writer__3920 const *)&t15; - t14 = (*t16); - t17 = t14; - t16 = (struct io_Writer__3920 const *)&t17; - memcpy(&t19, &t4, sizeof(uint8_t[8])); - memcpy((char *)&t18, t19, sizeof(uint8_t[8])); - t14 = (*t16); - t20.ptr = &t18[(uintptr_t)0ul]; - t20.len = (uintptr_t)8ul; - t21 = io_Writer_writeAll__7060(t14, t20); - memcpy(&t22, &t21, sizeof(uint16_t)); - if (t22) { - return t22; - } - t2 = (*t1); - t23 = t2; - t1 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *)&t23; - t24 = t1; - t8 = (struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const *const *)&t24; - t10 = (void const **)&t25.context; - t1 = (*t8); - t11 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t1->context; - t12 = (void const *)t11; - (*t10) = t12; - t13 = (nav__7071_51 (**)(void const *, nav__7071_40))&t25.writeFn; - (*t13) = &io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29___4060; - t14 = t25; - t26 = t14; - t16 = (struct io_Writer__3920 const *)&t26; - t14 = (*t16); - t22 = io_Writer_writeAll__7060(t14, a1); - memcpy(&t21, &t22, sizeof(uint16_t)); - if (t21) { - return t21; - } - return 0; -} - -static uint16_t bincode_serializeUnion__anon_3972__7072(struct io_GenericWriter_28_2aarray_list_ArrayListAligned_28u8_2cnull_29_2cerror_7bOutOfMemory_7d_2c_28function_20_27appendWrite_27_29_29__2005 const a0, struct shared_MarkerType__1953 const a1) { - uint64_t t4; - uint32_t t1; - uint16_t t2; - uint8_t t0; - bool t3; - t0 = a1.tag; - t1 = (uint32_t)t0; - t2 = bincode_serialize__anon_3275__6904(a0, t1); - if (t2) { - return t2; - } - t0 = a1.tag; - t3 = t0 == UINT8_C(0); - if (t3) { - t4 = a1.payload.SampleStart; - t2 = bincode_serialize__anon_3285__6909(a0, t4); - if (t2) { - return t2; - } - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - t0 = a1.tag; - t3 = t0 == UINT8_C(1); - if (t3) { - t4 = a1.payload.SampleEnd; - t2 = bincode_serialize__anon_3285__6909(a0, t4); - if (t2) { - return t2; - } - goto zig_block_1; - } - goto zig_block_1; - - zig_block_1:; - t0 = a1.tag; - t3 = t0 == UINT8_C(2); - if (t3) { - t4 = a1.payload.BenchmarkStart; - t2 = bincode_serialize__anon_3285__6909(a0, t4); - if (t2) { - return t2; - } - goto zig_block_2; - } - goto zig_block_2; - - zig_block_2:; - t0 = a1.tag; - t3 = t0 == UINT8_C(3); - if (t3) { - t4 = a1.payload.BenchmarkEnd; - t2 = bincode_serialize__anon_3285__6909(a0, t4); - if (t2) { - return t2; - } - goto zig_block_3; - } - goto zig_block_3; - - zig_block_3:; - return 0; -} - -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_appendSlice__3908(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, nav__3908_41 const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t2; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - uintptr_t t3; - uint16_t t4; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (*t1); - t3 = a1.len; - t4 = array_list_ArrayListAligned_28u8_2cnull_29_ensureUnusedCapacity__3927(t2, t3); - if (t4) { - return t4; - } - t2 = (*t1); - array_list_ArrayListAligned_28u8_2cnull_29_appendSliceAssumeCapacity__3909(t2, a1); - return 0; -} - -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureUnusedCapacity__3927(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, uintptr_t const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t2; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - nav__3927_43 *t3; - nav__3927_43 t4; - uintptr_t t5; - nav__3927_52 t6; - uint16_t t7; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (*t1); - t3 = (nav__3927_43 *)&a0->items; - t4 = (*t3); - t5 = t4.len; - t6 = array_list_addOrOom__3852(t5, a1); - if (t6.error) { - t7 = t6.error; - return t7; - } - t5 = t6.payload; - t7 = array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacity__3925(t2, t5); - return t7; -} - -static void array_list_ArrayListAligned_28u8_2cnull_29_appendSliceAssumeCapacity__3909(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, nav__3909_41 const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - nav__3909_47 *t2; - nav__3909_47 t3; - uintptr_t t4; - uintptr_t t5; - uintptr_t t7; - uintptr_t *t6; - uint64_t t8; - uint64_t t9; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t11; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - uint8_t *t12; - uint8_t const *t13; - bool t10; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (nav__3909_47 *)&a0->items; - t3 = (*t2); - t4 = t3.len; - t5 = a1.len; - t5 = t4 + t5; - t6 = (uintptr_t *)&a0->capacity; - t7 = (*t6); - t8 = t5; - t9 = t7; - t10 = t8 <= t9; - debug_assert__180(t10); - t11 = (*t1); - t2 = (nav__3909_47 *)&t11->items; - t6 = &t2->len; - (*t6) = t5; - t11 = (*t1); - t2 = (nav__3909_47 *)&t11->items; - t5 = a1.len; - t3 = (*t2); - t12 = t3.ptr; - t12 = (uint8_t *)(((uintptr_t)t12) + (t4*sizeof(uint8_t))); - t3.ptr = t12; - t3.len = t5; - t13 = a1.ptr; - if (t3.len != 0) memcpy(t3.ptr, t13, t3.len * sizeof(uint8_t)); - return; -} - -static nav__3852_38 array_list_addOrOom__3852(uintptr_t const a0, uintptr_t const a1) { - nav__3852_42 t2; - uintptr_t t3; - uintptr_t t0; - uintptr_t const *t5; - uint8_t const *t6; - nav__3852_38 t8; - uint8_t t4; - uint8_t t1; - bool t7; - t2.f1 = zig_addo_u64(&t2.f0, a0, a1, UINT8_C(64)); - t3 = t2.f0; - t0 = t3; - t4 = t2.f1; - t1 = t4; - t5 = (uintptr_t const *)&t0; - t6 = (uint8_t const *)&t1; - t4 = (*t6); - t7 = t4 != UINT8_C(0); - if (t7) { - return (nav__3852_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_OutOfMemory}; - } - goto zig_block_0; - - zig_block_0:; - t3 = (*t5); - t8.payload = t3; - t8.error = UINT16_C(0); - return t8; -} - -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacity__3925(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, uintptr_t const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - uintptr_t *t2; - uintptr_t t3; - uint64_t t4; - uint64_t t5; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t7; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - uint16_t t8; - bool t6; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (uintptr_t *)&a0->capacity; - t3 = (*t2); - t4 = t3; - t5 = a1; - t6 = t4 >= t5; - if (t6) { - return 0; - } - goto zig_block_0; - - zig_block_0:; - t2 = (uintptr_t *)&a0->capacity; - t3 = (*t2); - t3 = array_list_ArrayListAlignedUnmanaged_28u8_2cnull_29_growCapacity__7131(t3, a1); - t7 = (*t1); - t8 = array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacityPrecise__3926(t7, t3); - return t8; -} - -static uintptr_t array_list_ArrayListAlignedUnmanaged_28u8_2cnull_29_growCapacity__7131(uintptr_t const a0, uintptr_t const a1) { - uintptr_t t1; - uintptr_t t2; - uintptr_t t0; - uint64_t t3; - uint64_t t4; - bool t5; - t0 = a0; - zig_loop_6: - t1 = t0; - t2 = t0; - t2 = t2 / (uintptr_t)2ul; - t2 = t2 + (uintptr_t)128ul; - t2 = zig_adds_u64(t1, t2, UINT8_C(64)); - t0 = t2; - t2 = t0; - t3 = t2; - t4 = a1; - t5 = t3 >= t4; - if (t5) { - t2 = t0; - return t2; - } - goto zig_block_0; - - zig_block_0:; - goto zig_loop_6; -} - -static uint16_t array_list_ArrayListAligned_28u8_2cnull_29_ensureTotalCapacityPrecise__3926(struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const a0, uintptr_t const a1) { - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *t1; - uintptr_t *t2; - uintptr_t t3; - uint64_t t4; - uint64_t t5; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t7; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *t0; - struct array_list_ArrayListAligned_28u8_2cnull_29__1974 t8; - nav__3926_43 t9; - nav__3926_43 t12; - nav__3926_43 t20; - nav__3926_43 t21; - nav__3926_43 t18; - struct mem_Allocator__565 *t10; - struct mem_Allocator__565 t11; - nav__3926_43 *t13; - uint8_t **t14; - uint8_t *t15; - nav__3926_55 t16; - nav__3926_43 const *t19; - uint16_t t17; - bool t6; - t0 = a0; - t1 = (struct array_list_ArrayListAligned_28u8_2cnull_29__1974 *const *)&t0; - t2 = (uintptr_t *)&a0->capacity; - t3 = (*t2); - t4 = t3; - t5 = a1; - t6 = t4 >= t5; - if (t6) { - return 0; - } - goto zig_block_0; - - zig_block_0:; - t7 = (*t1); - t8 = (*t7); - t9 = array_list_ArrayListAligned_28u8_2cnull_29_allocatedSlice__3936(t8); - t7 = (*t1); - t10 = (struct mem_Allocator__565 *)&t7->allocator; - t11 = (*t10); - t12 = mem_Allocator_remap__anon_4029__7158(t11, t9, a1); - t6 = t12.ptr != NULL; - if (t6) { - t9 = t12; - t7 = (*t1); - t13 = (nav__3926_43 *)&t7->items; - t14 = &t13->ptr; - t15 = t9.ptr; - (*t14) = t15; - t7 = (*t1); - t2 = (uintptr_t *)&t7->capacity; - t3 = t9.len; - (*t2) = t3; - goto zig_block_1; - } - t7 = (*t1); - t10 = (struct mem_Allocator__565 *)&t7->allocator; - t11 = (*t10); - t16 = mem_Allocator_alignedAlloc__anon_4034__7159(t11, a1); - if (t16.error) { - t17 = t16.error; - return t17; - } - t12 = t16.payload; - t18 = t12; - t19 = (nav__3926_43 const *)&t18; - t13 = (nav__3926_43 *)&a0->items; - t20 = (*t13); - t3 = t20.len; - t20 = (*t19); - t15 = t20.ptr; - t15 = (uint8_t *)(((uintptr_t)t15) + ((uintptr_t)0ul*sizeof(uint8_t))); - t20.ptr = t15; - t20.len = t3; - t13 = (nav__3926_43 *)&a0->items; - t21 = (*t13); - t15 = t21.ptr; - if (t20.len != 0) memcpy(t20.ptr, t15, t20.len * sizeof(uint8_t)); - t7 = (*t1); - t10 = (struct mem_Allocator__565 *)&t7->allocator; - t11 = (*t10); - mem_Allocator_free__anon_2159__4104(t11, t9); - t7 = (*t1); - t13 = (nav__3926_43 *)&t7->items; - t14 = &t13->ptr; - t15 = t12.ptr; - (*t14) = t15; - t7 = (*t1); - t2 = (uintptr_t *)&t7->capacity; - t3 = t12.len; - (*t2) = t3; - goto zig_block_1; - - zig_block_1:; - return 0; -} - -static nav__7158_39 mem_Allocator_remap__anon_4029__7158(struct mem_Allocator__565 const a0, nav__7158_39 const a1, uintptr_t const a2) { - struct mem_Allocator__565 const *t1; - nav__7158_39 const *t3; - uint64_t t4; - struct mem_Allocator__565 t6; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t15; - nav__7158_39 t7; - nav__7158_39 t10; - nav__7158_39 t2; - uint8_t *t8; - uint8_t *t20; - uint8_t *t21; - uint8_t *t22; - void *t9; - uintptr_t t11; - uintptr_t t13; - nav__7158_50 t12; - struct mem_Allocator_VTable__568 const *const *t16; - struct mem_Allocator_VTable__568 const *t17; - uint8_t *(*const *t18)(void *, nav__7158_39, uint8_t, uintptr_t, uintptr_t); - uint8_t *(*t19)(void *, nav__7158_39, uint8_t, uintptr_t, uintptr_t); - uint8_t *const *t23; - bool t5; - uint8_t t14; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = a1; - t3 = (nav__7158_39 const *)&t2; - t4 = a2; - t5 = t4 == UINT64_C(0); - if (t5) { - t6 = (*t1); - mem_Allocator_free__anon_2159__4104(t6, a1); - t7 = (*t3); - t8 = t7.ptr; - t8 = (uint8_t *)(((uintptr_t)t8) + ((uintptr_t)0ul*sizeof(uint8_t))); - t9 = (void *)t8; - t7.ptr = t9; - t7.len = (uintptr_t)0ul; - t10 = t7; - return t10; - } - goto zig_block_0; - - zig_block_0:; - t11 = a1.len; - t4 = t11; - t5 = t4 == UINT64_C(0); - if (t5) { - return (nav__7158_39){NULL,(uintptr_t)0xaaaaaaaaaaaaaaaaul}; - } - goto zig_block_1; - - zig_block_1:; - t10 = mem_sliceAsBytes__anon_2966__5249(a1); - t12 = math_mul__anon_3472__6977((uintptr_t)1ul, a2); - t5 = t12.error == UINT16_C(0); - if (t5) { - t13 = t12.payload; - t11 = t13; - goto zig_block_2; - } - return (nav__7158_39){NULL,(uintptr_t)0xaaaaaaaaaaaaaaaaul}; - - zig_block_2:; - t6 = (*t1); - t14 = mem_Alignment_fromByteUnits__1046((uintptr_t)1ul); - t13 = (uintptr_t)zig_return_address(); - t15 = t6; - t1 = (struct mem_Allocator__565 const *)&t15; - t16 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t17 = (*t16); - t18 = (uint8_t *(*const *)(void *, nav__7158_39, uint8_t, uintptr_t, uintptr_t))&t17->remap; - t19 = (*t18); - t9 = t6.ptr; - t20 = t19(t9, t10, t14, t11, t13); - t5 = t20 != NULL; - if (t5) { - t21 = t20; - t8 = t21; - goto zig_block_3; - } - return (nav__7158_39){NULL,(uintptr_t)0xaaaaaaaaaaaaaaaaul}; - - zig_block_3:; - t22 = t8; - t23 = (uint8_t *const *)&t22; - t8 = (*t23); - t8 = (uint8_t *)(((uintptr_t)t8) + ((uintptr_t)0ul*sizeof(uint8_t))); - t10.ptr = t8; - t10.len = t11; - memcpy(&t7, &t10, sizeof(nav__7158_39)); - t7 = mem_bytesAsSlice__anon_4049__7160(t7); - t10 = t7; - return t10; -} - -static nav__7159_40 mem_Allocator_alignedAlloc__anon_4034__7159(struct mem_Allocator__565 const a0, uintptr_t const a1) { - struct mem_Allocator__565 const *t1; - struct mem_Allocator__565 t2; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t5; - uintptr_t t3; - nav__7159_40 t4; - nav__7159_40 t8; - nav__7159_51 t6; - uint8_t *t9; - uint8_t *t10; - uint8_t *const *t11; - nav__7159_39 t12; - uint16_t t7; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = (*t1); - t3 = (uintptr_t)zig_return_address(); - t5 = t2; - t1 = (struct mem_Allocator__565 const *)&t5; - t2 = (*t1); - t6 = mem_Allocator_allocWithSizeAndAlignment__anon_2953__5248(t2, a1, t3); - if (t6.error) { - t7 = t6.error; - t8.payload = (nav__7159_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t8.error = t7; - t4 = t8; - goto zig_block_0; - } - t9 = t6.payload; - t10 = t9; - t11 = (uint8_t *const *)&t10; - t9 = (*t11); - t9 = (uint8_t *)(((uintptr_t)t9) + ((uintptr_t)0ul*sizeof(uint8_t))); - t12.ptr = t9; - t12.len = a1; - t8.payload = t12; - t8.error = UINT16_C(0); - t4 = t8; - goto zig_block_0; - - zig_block_0:; - return t4; -} - -static nav__7160_39 mem_bytesAsSlice__anon_4049__7160(nav__7160_39 const a0) { - uintptr_t t0; - uint64_t t1; - uint8_t *t4; - uint8_t *t5; - uint8_t *const *t6; - nav__7160_39 t7; - bool t2; - bool t3; - t0 = a0.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - t3 = true; - goto zig_block_1; - } - t3 = false; - goto zig_block_1; - - zig_block_1:; - if (t3) { - return (nav__7160_39){(uint8_t *)((void const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),(uintptr_t)0ul}; - } - goto zig_block_0; - - zig_block_0:; - t4 = a0.ptr; - t5 = t4; - t6 = (uint8_t *const *)&t5; - t0 = a0.len; - t0 = t0 / (uintptr_t)1ul; - t4 = (*t6); - t4 = (uint8_t *)(((uintptr_t)t4) + ((uintptr_t)0ul*sizeof(uint8_t))); - t7.ptr = t4; - t7.len = t0; - return t7; -} - -void c_instrument_hooks_deinit__240(struct instruments_root_InstrumentHooks__547 *const a0) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t4; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t5; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t6; - struct instruments_perf_PerfInstrument__559 *t8; - bool t0; - uint8_t t7; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t4 = (*t3); - t5 = t4; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t5; - t6 = (*t4); - t7 = t6.tag; - switch (t7) { - case UINT8_C(0): { - goto zig_block_1; - } - case UINT8_C(1): { - t4 = (*t3); - t8 = (struct instruments_perf_PerfInstrument__559 *)&t4->payload.perf; - instruments_perf_PerfInstrument_deinit__752(t8); - goto zig_block_1; - } - case UINT8_C(2): { - goto zig_block_1; - } - default: zig_unreachable(); - } - - zig_block_1:; - mem_Allocator_destroy__anon_2777__4228((struct mem_Allocator__565){((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}, t1); - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return; -} - -bool c_instrument_hooks_is_instrumented__241(struct instruments_root_InstrumentHooks__547 *const a0) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t4; - struct instruments_perf_PerfInstrument__559 t8; - struct instruments_perf_PerfInstrument__559 t9; - bool t0; - bool t6; - bool t7; - uint8_t t5; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t1 = (*t3); - t4 = (*t1); - t5 = t4.tag; - switch (t5) { - case UINT8_C(0): { - t5 = running_on_valgrind(); - t7 = t5 > UINT8_C(0); - t6 = t7; - goto zig_block_2; - } - case UINT8_C(1): { - t8 = t4.payload.perf; - t9 = t8; - t7 = instruments_perf_PerfInstrument_is_instrumented__754(&t9); - t0 = t7; - goto zig_block_1; - } - case UINT8_C(2): { - t6 = false; - goto zig_block_2; - } - default: zig_unreachable(); - } - - zig_block_2:; - t0 = t6; - goto zig_block_1; - - zig_block_1:; - return t0; - } - goto zig_block_0; - - zig_block_0:; - return false; -} - -static zig_cold uint16_t instruments_perf_PerfInstrument_start_benchmark__755(struct instruments_perf_PerfInstrument__559 *const a0) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct fifo_UnixPipe_Reader__602 *t5; - uint16_t t4; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4 = fifo_UnixPipe_Writer_sendCmd__1080(t3, (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(1)}); - if (t4) { - return t4; - } - t2 = (*t1); - t5 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t4 = fifo_UnixPipe_Reader_waitForAck__1087(t5, (nav__755_71){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t4) { - return t4; - } - return 0; -} - -uint8_t c_instrument_hooks_start_benchmark__242(struct instruments_root_InstrumentHooks__547 *const a0) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t5; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t6; - struct instruments_perf_PerfInstrument__559 *t8; - uint16_t t4; - uint16_t t9; - uint16_t t10; - bool t0; - uint8_t t7; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t1 = (*t3); - t5 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t5; - t6 = (*t1); - t7 = t6.tag; - t0 = t7 == UINT8_C(1); - if (t0) { - t1 = (*t3); - t8 = (struct instruments_perf_PerfInstrument__559 *)&t1->payload.perf; - t9 = instruments_perf_PerfInstrument_start_benchmark__755(t8); - memcpy(&t10, &t9, sizeof(uint16_t)); - t4 = t10; - goto zig_block_2; - } - t6 = (*t1); - t7 = t6.tag; - t0 = t7 == UINT8_C(0); - if (t0) { - t0 = features_is_feature_enabled__326(UINT64_C(0)); - t0 = !t0; - if (t0) { - callgrind_zero_stats(); - callgrind_start_instrumentation(); - goto zig_block_5; - } - goto zig_block_5; - - zig_block_5:; - t4 = 0; - goto zig_block_2; - } - goto zig_block_4; - - zig_block_4:; - goto zig_block_3; - - zig_block_3:; - t4 = 0; - goto zig_block_2; - - zig_block_2:; - memcpy(&t10, &t4, sizeof(uint16_t)); - t0 = t10 == UINT16_C(0); - if (t0) { - goto zig_block_1; - } - return UINT8_C(1); - - zig_block_1:; - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return UINT8_C(0); -} - -static bool features_is_feature_enabled__326(uint64_t const a0) { - uint64_t t0; - uint64_t t1; - uintptr_t t2; - bool t3; - t0 = (*&features_features__324); - t1 = a0; - t2 = t1; - t3 = bit_set_IntegerBitSet_2864_29_isSet__361(t0, t2); - return t3; -} - -static bool bit_set_IntegerBitSet_2864_29_isSet__361(uint64_t const a0, uintptr_t const a1) { - uint64_t t0; - uint64_t t2; - bool t1; - t0 = a1; - t1 = t0 < UINT64_C(64); - debug_assert__180(t1); - t0 = zig_wrap_u64((uint64_t)a0, UINT8_C(64)); - t2 = bit_set_IntegerBitSet_2864_29_maskBit__385(a1); - t2 = t0 & t2; - t1 = t2 != UINT64_C(0); - return t1; -} - -static zig_cold uint16_t instruments_perf_PerfInstrument_stop_benchmark__756(struct instruments_perf_PerfInstrument__559 *const a0) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct fifo_UnixPipe_Reader__602 *t5; - uint16_t t4; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4 = fifo_UnixPipe_Writer_sendCmd__1080(t3, (struct shared_Command__1946){{{{(uint8_t const *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},UINT32_C(0xaaaaaaaa)}},UINT8_C(2)}); - if (t4) { - return t4; - } - t2 = (*t1); - t5 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t4 = fifo_UnixPipe_Reader_waitForAck__1087(t5, (nav__756_71){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t4) { - return t4; - } - return 0; -} - -uint8_t c_instrument_hooks_stop_benchmark__243(struct instruments_root_InstrumentHooks__547 *const a0) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t5; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t6; - struct instruments_perf_PerfInstrument__559 *t8; - uint16_t t4; - uint16_t t9; - uint16_t t10; - bool t0; - uint8_t t7; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t1 = (*t3); - t5 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t5; - t6 = (*t1); - t7 = t6.tag; - t0 = t7 == UINT8_C(0); - if (t0) { - t0 = features_is_feature_enabled__326(UINT64_C(0)); - t0 = !t0; - if (t0) { - callgrind_stop_instrumentation(); - goto zig_block_4; - } - goto zig_block_4; - - zig_block_4:; - t4 = 0; - goto zig_block_2; - } - t6 = (*t1); - t7 = t6.tag; - t0 = t7 == UINT8_C(1); - if (t0) { - t1 = (*t3); - t8 = (struct instruments_perf_PerfInstrument__559 *)&t1->payload.perf; - t9 = instruments_perf_PerfInstrument_stop_benchmark__756(t8); - memcpy(&t10, &t9, sizeof(uint16_t)); - t4 = t10; - goto zig_block_2; - } - goto zig_block_5; - - zig_block_5:; - goto zig_block_3; - - zig_block_3:; - t4 = 0; - goto zig_block_2; - - zig_block_2:; - memcpy(&t10, &t4, sizeof(uint16_t)); - t0 = t10 == UINT16_C(0); - if (t0) { - goto zig_block_1; - } - return UINT8_C(1); - - zig_block_1:; - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return UINT8_C(0); -} - -static uint16_t instruments_perf_PerfInstrument_set_executed_benchmark__757(struct instruments_perf_PerfInstrument__559 *const a0, uint32_t const a1, uint8_t const *const a2) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - nav__757_56 t4; - nav__757_56 t5; - struct shared_Command__struct_1949__1949 t6; - struct shared_Command__1946 t7; - struct fifo_UnixPipe_Reader__602 *t9; - uint16_t t8; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4 = mem_span__anon_4156__7165(a2); - memcpy(&t5, &t4, sizeof(nav__757_56)); - t6.uri = t5; - t6.pid = a1; - t7.tag = UINT8_C(0); - t7.payload.ExecutedBenchmark = t6; - t8 = fifo_UnixPipe_Writer_sendCmd__1080(t3, t7); - if (t8) { - return t8; - } - t2 = (*t1); - t9 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t8 = fifo_UnixPipe_Reader_waitForAck__1087(t9, (nav__757_71){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t8) { - return t8; - } - return 0; -} - -uint8_t c_instrument_hooks_set_executed_benchmark__244(struct instruments_root_InstrumentHooks__547 *const a0, uint32_t const a1, uint8_t const *const a2) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t5; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t6; - uint8_t const *t8; - struct instruments_perf_PerfInstrument__559 *t9; - uint16_t t4; - uint16_t t10; - bool t0; - uint8_t t7; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t1 = (*t3); - t5 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t5; - t6 = (*t1); - t7 = t6.tag; - switch (t7) { - case UINT8_C(0): { - t8 = (uint8_t const *)a2; - callgrind_dump_stats_at(t8); - goto zig_block_3; - } - case UINT8_C(1): { - t1 = (*t3); - t9 = (struct instruments_perf_PerfInstrument__559 *)&t1->payload.perf; - t10 = instruments_perf_PerfInstrument_set_executed_benchmark__757(t9, a1, a2); - if (t10) { - t4 = t10; - goto zig_block_2; - } - goto zig_block_3; - } - case UINT8_C(2): { - goto zig_block_3; - } - default: zig_unreachable(); - } - - zig_block_3:; - t4 = 0; - goto zig_block_2; - - zig_block_2:; - memcpy(&t10, &t4, sizeof(uint16_t)); - t0 = t10 == UINT16_C(0); - if (t0) { - goto zig_block_1; - } - return UINT8_C(1); - - zig_block_1:; - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return UINT8_C(0); -} - -static nav__7165_39 mem_span__anon_4156__7165(uint8_t const *const a0) { - uint8_t const *const *t1; - uintptr_t t2; - uint8_t const *t3; - uint8_t const *t0; - nav__7165_39 t4; - t0 = a0; - t1 = (uint8_t const *const *)&t0; - t2 = mem_len__anon_4165__7166(a0); - t3 = (*t1); - t3 = (uint8_t const *)(((uintptr_t)t3) + ((uintptr_t)0ul*sizeof(uint8_t))); - t4.ptr = t3; - t4.len = t2; - return t4; -} - -static uintptr_t mem_len__anon_4165__7166(uint8_t const *const a0) { - uint8_t const *t1; - uintptr_t t2; - bool t0; - t0 = a0 != NULL; - debug_assert__180(t0); - t1 = (uint8_t const *)a0; - t2 = mem_indexOfSentinel__anon_4173__7167(t1); - return t2; -} - -static uintptr_t mem_indexOfSentinel__anon_4173__7167(uint8_t const *const a0) { - static uint8_t const t11[32] = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; - static uint8_t const t18[32] = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; - uint8_t const *const *t1; - uintptr_t t4; - uintptr_t t6; - uintptr_t t16; - uintptr_t t2; - uint8_t const *t5; - uint8_t const *t0; - uint64_t t7; - uint8_t const (*t8)[32]; - uint8_t const (*t17)[32]; - bool t3; - uint8_t t9[32]; - uint8_t t10[32]; - bool t12[32]; - nav__7167_45 t13; - nav__7167_47 t14; - uint8_t t15; - t0 = a0; - t1 = (uint8_t const *const *)&t0; - t2 = (uintptr_t)0ul; - t3 = math_isPowerOfTwo__anon_4184__7168(); - if (t3) { - debug_assert__180(true); - t4 = t2; - t5 = (*t1); - t5 = (uint8_t const *)&t5[t4]; - t4 = (uintptr_t)t5; - t6 = t4 & (uintptr_t)4095ul; - t7 = t6; - t3 = t7 <= UINT64_C(4064); - if (t3) { - t6 = t2; - t5 = (*t1); - t5 = (uint8_t const *)(((uintptr_t)t5) + (t6*sizeof(uint8_t))); - t8 = (uint8_t const (*)[32])t5; - memcpy(t9, (const char *)t8, sizeof(uint8_t[32])); - memcpy(&t10, &t9, sizeof(uint8_t[32])); - for (t6 = (uintptr_t)0ul; t6 < (uintptr_t)32ul; t6 += (uintptr_t)1ul) { - t12[t6] = t10[t6] == t11[t6]; - } - t3 = false; - for (t6 = (uintptr_t)0ul; t6 < (uintptr_t)32ul; t6 += (uintptr_t)1ul) { - t3 |= t12[t6]; - } - if (t3) { - t4 = t2; - memcpy(t13.array, t12, sizeof(nav__7167_45)); - t14 = simd_firstTrue__anon_4396__7533(t13); - t15 = t14.payload; - t6 = (uintptr_t)t15; - t6 = t4 + t6; - return t6; - } - goto zig_block_2; - - zig_block_2:; - t6 = t2; - t16 = mem_alignForward__anon_4399__7534(t4, (uintptr_t)32ul); - t4 = t16 - t4; - t4 = t4 / (uintptr_t)1ul; - t4 = t6 + t4; - t2 = t4; - goto zig_block_1; - } - zig_loop_79: - t4 = t2; - t5 = (*t1); - t5 = (uint8_t const *)&t5[t4]; - t4 = (uintptr_t)t5; - t4 = t4 & (uintptr_t)31ul; - t7 = t4; - t3 = t7 != UINT64_C(0); - if (t3) { - t4 = t2; - t15 = a0[t4]; - t3 = t15 == UINT8_C(0); - if (t3) { - t4 = t2; - return t4; - } - goto zig_block_5; - - zig_block_5:; - t4 = t2; - t4 = t4 + (uintptr_t)1ul; - t2 = t4; - goto zig_block_4; - } - goto zig_block_3; - - zig_block_4:; - goto zig_loop_79; - - zig_block_3:; - goto zig_block_1; - - zig_block_1:; - t6 = t2; - t5 = (*t1); - t5 = (uint8_t const *)&t5[t6]; - t6 = (uintptr_t)t5; - t3 = mem_isAligned__915(t6, (uintptr_t)32ul); - debug_assert__180(t3); - zig_loop_114: - t6 = t2; - t5 = (*t1); - t5 = (uint8_t const *)(((uintptr_t)t5) + (t6*sizeof(uint8_t))); - t8 = (uint8_t const (*)[32])t5; - t17 = (uint8_t const (*)[32])t8; - memcpy(t10, (const char *)t17, sizeof(uint8_t[32])); - for (t6 = (uintptr_t)0ul; t6 < (uintptr_t)32ul; t6 += (uintptr_t)1ul) { - t12[t6] = t10[t6] == t18[t6]; - } - t3 = false; - for (t6 = (uintptr_t)0ul; t6 < (uintptr_t)32ul; t6 += (uintptr_t)1ul) { - t3 |= t12[t6]; - } - if (t3) { - t6 = t2; - memcpy(t13.array, t12, sizeof(nav__7167_45)); - t14 = simd_firstTrue__anon_4396__7533(t13); - t15 = t14.payload; - t4 = (uintptr_t)t15; - t4 = t6 + t4; - return t4; - } - goto zig_block_6; - - zig_block_6:; - t6 = t2; - t6 = t6 + (uintptr_t)32ul; - t2 = t6; - goto zig_loop_114; - } - goto zig_block_0; - - zig_block_0:; - zig_loop_145: - t16 = t2; - t15 = a0[t16]; - t3 = t15 != UINT8_C(0); - if (t3) { - t16 = t2; - t16 = t16 + (uintptr_t)1ul; - t2 = t16; - goto zig_block_8; - } - goto zig_block_7; - - zig_block_8:; - goto zig_loop_145; - - zig_block_7:; - t16 = t2; - return t16; -} - -static bool math_isPowerOfTwo__anon_4184__7168(void) { - debug_assert__180(true); - return true; -} - -static nav__7533_38 simd_firstTrue__anon_4396__7533(nav__7533_40 const a0) { - static uint8_t const t2[32] = {UINT8_C(0),UINT8_C(1),UINT8_C(2),UINT8_C(3),UINT8_C(4),UINT8_C(5),UINT8_C(6),UINT8_C(7),UINT8_C(8),UINT8_C(9),UINT8_C(10),UINT8_C(11),UINT8_C(12),UINT8_C(13),UINT8_C(14),UINT8_C(15),UINT8_C(16),UINT8_C(17),UINT8_C(18),UINT8_C(19),UINT8_C(20),UINT8_C(21),UINT8_C(22),UINT8_C(23),UINT8_C(24),UINT8_C(25),UINT8_C(26),UINT8_C(27),UINT8_C(28),UINT8_C(29),UINT8_C(30),UINT8_C(31)}; - static uint8_t const t3[32] = {UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31),UINT8_C(31)}; - uintptr_t t1; - bool t0; - uint8_t t4[32]; - uint8_t t5; - nav__7533_38 t6; - t0 = false; - for (t1 = (uintptr_t)0ul; t1 < (uintptr_t)32ul; t1 += (uintptr_t)1ul) { - t0 |= a0.array[t1]; - } - t0 = !t0; - if (t0) { - return (nav__7533_38){true,UINT8_C(0xa)}; - } - goto zig_block_0; - - zig_block_0:; - for (t1 = (uintptr_t)0ul; t1 < (uintptr_t)32ul; t1 += (uintptr_t)1ul) { - t4[t1] = a0.array[t1] ? t2[t1] : t3[t1]; - } - t5 = UINT8_C(31); - for (t1 = (uintptr_t)0ul; t1 < (uintptr_t)32ul; t1 += (uintptr_t)1ul) { - t5 = t5 < t4[t1] ? t5 : t4[t1]; - } - t6.is_null = false; - t6.payload = t5; - return t6; -} - -static uintptr_t mem_alignForward__anon_4399__7534(uintptr_t const a0, uintptr_t const a1) { - uintptr_t t1; - bool t0; - t0 = mem_isValidAlignGeneric__anon_4457__7535(a1); - debug_assert__180(t0); - t1 = a1 - (uintptr_t)1ul; - t1 = a0 + t1; - t1 = mem_alignBackward__anon_4458__7536(t1, a1); - return t1; -} - -static bool mem_isAligned__915(uintptr_t const a0, uintptr_t const a1) { - uint64_t t0; - uint64_t t1; - bool t2; - t0 = a0; - t1 = a1; - t2 = mem_isAlignedGeneric__anon_4464__7537(t0, t1); - return t2; -} - -static bool mem_isValidAlignGeneric__anon_4457__7535(uintptr_t const a0) { - uint64_t t0; - bool t1; - bool t2; - t0 = a0; - t1 = t0 > UINT64_C(0); - if (t1) { - t1 = math_isPowerOfTwo__anon_3486__6979(a0); - t2 = t1; - goto zig_block_0; - } - t2 = false; - goto zig_block_0; - - zig_block_0:; - return t2; -} - -static uintptr_t mem_alignBackward__anon_4458__7536(uintptr_t const a0, uintptr_t const a1) { - uintptr_t t1; - bool t0; - t0 = mem_isValidAlignGeneric__anon_4457__7535(a1); - debug_assert__180(t0); - t1 = a1 - (uintptr_t)1ul; - t1 = zig_not_u64(t1, UINT8_C(64)); - t1 = a0 & t1; - return t1; -} - -static bool mem_isAlignedGeneric__anon_4464__7537(uint64_t const a0, uint64_t const a1) { - uint64_t t0; - bool t1; - t0 = mem_alignBackward__anon_4466__7538(a0, a1); - t1 = t0 == a0; - return t1; -} - -static uint64_t mem_alignBackward__anon_4466__7538(uint64_t const a0, uint64_t const a1) { - uint64_t t1; - bool t0; - t0 = mem_isValidAlignGeneric__anon_4468__7539(a1); - debug_assert__180(t0); - t1 = a1 - UINT64_C(1); - t1 = zig_not_u64(t1, UINT8_C(64)); - t1 = a0 & t1; - return t1; -} - -static bool mem_isValidAlignGeneric__anon_4468__7539(uint64_t const a0) { - bool t0; - bool t1; - t0 = a0 > UINT64_C(0); - if (t0) { - t0 = math_isPowerOfTwo__anon_4469__7540(a0); - t1 = t0; - goto zig_block_0; - } - t1 = false; - goto zig_block_0; - - zig_block_0:; - return t1; -} - -static bool math_isPowerOfTwo__anon_4469__7540(uint64_t const a0) { - uint64_t t1; - bool t0; - t0 = a0 > UINT64_C(0); - debug_assert__180(t0); - t1 = a0 - UINT64_C(1); - t1 = a0 & t1; - t0 = t1 == UINT64_C(0); - return t0; -} - -uint8_t c_instrument_hooks_executed_benchmark__245(struct instruments_root_InstrumentHooks__547 *const a0, uint32_t const a1, uint8_t const *const a2) { - uint8_t t0; - t0 = c_instrument_hooks_set_executed_benchmark__244(a0, a1, a2); - return t0; -} - -static uint16_t instruments_perf_PerfInstrument_set_integration__758(struct instruments_perf_PerfInstrument__559 *const a0, uint8_t const *const a1, uint8_t const *const a2) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - nav__758_56 t4; - nav__758_56 t5; - nav__758_56 t6; - struct shared_Command__struct_1950__1950 t7; - struct shared_Command__1946 t8; - struct fifo_UnixPipe_Reader__602 *t10; - uint16_t t9; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4 = mem_span__anon_4156__7165(a1); - t5 = mem_span__anon_4156__7165(a2); - memcpy(&t6, &t4, sizeof(nav__758_56)); - memcpy(&t4, &t5, sizeof(nav__758_56)); - t7.name = t6; - t7.version = t4; - t8.tag = UINT8_C(5); - t8.payload.SetIntegration = t7; - t9 = fifo_UnixPipe_Writer_sendCmd__1080(t3, t8); - if (t9) { - return t9; - } - t2 = (*t1); - t10 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t9 = fifo_UnixPipe_Reader_waitForAck__1087(t10, (nav__758_71){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t9) { - return t9; - } - return 0; -} - -uint8_t c_instrument_hooks_set_integration__246(struct instruments_root_InstrumentHooks__547 *const a0, uint8_t const *const a1, uint8_t const *const a2) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t5; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct instruments_root_InstrumentHooks__547 t6; - struct instruments_valgrind_ValgrindInstrument__554 *t8; - struct instruments_valgrind_ValgrindInstrument__554 t9; - struct instruments_valgrind_ValgrindInstrument__554 t11; - struct instruments_valgrind_ValgrindInstrument__554 const *t12; - struct mem_Allocator__565 t13; - nav__246_62 t14; - nav__246_67 t15; - nav__246_65 t17; - uint8_t *t18; - uint8_t const *t19; - struct mem_Allocator__565 const *t20; - struct instruments_perf_PerfInstrument__559 *t21; - uint16_t t4; - uint16_t t10; - uint16_t t16; - bool t0; - uint8_t t7; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - t1 = (*t3); - t5 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t5; - t6 = (*t1); - t7 = t6.tag; - switch (t7) { - case UINT8_C(0): { - t1 = (*t3); - t8 = (struct instruments_valgrind_ValgrindInstrument__554 *)&t1->payload.valgrind; - t9 = (*t8); - t11 = t9; - t12 = (struct instruments_valgrind_ValgrindInstrument__554 const *)&t11; - t13 = t9.allocator; - t14.f0 = a1; - t14.f1 = a2; - t15 = fmt_allocPrintZ__anon_4506__7541(t13, t14); - if (t15.error) { - t16 = t15.error; - t10 = t16; - goto zig_block_4; - } - t17 = t15.payload; - t18 = t17.ptr; - t19 = (uint8_t const *)t18; - callgrind_dump_stats_at(t19); - t20 = (struct mem_Allocator__565 const *)&t12->allocator; - t13 = (*t20); - mem_Allocator_free__anon_4508__7542(t13, t17); - t10 = 0; - goto zig_block_4; - - zig_block_4:; - memcpy(&t16, &t10, sizeof(uint16_t)); - if (t16) { - t4 = t16; - goto zig_block_2; - } - goto zig_block_3; - } - case UINT8_C(1): { - t1 = (*t3); - t21 = (struct instruments_perf_PerfInstrument__559 *)&t1->payload.perf; - t16 = instruments_perf_PerfInstrument_set_integration__758(t21, a1, a2); - if (t16) { - t4 = t16; - goto zig_block_2; - } - goto zig_block_3; - } - case UINT8_C(2): { - goto zig_block_3; - } - default: zig_unreachable(); - } - - zig_block_3:; - t4 = 0; - goto zig_block_2; - - zig_block_2:; - memcpy(&t16, &t4, sizeof(uint16_t)); - t0 = t16 == UINT16_C(0); - if (t0) { - goto zig_block_1; - } - return UINT8_C(1); - - zig_block_1:; - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return UINT8_C(0); -} - -static nav__7541_40 fmt_allocPrintZ__anon_4506__7541(struct mem_Allocator__565 const a0, nav__7541_43 const a1) { - nav__7541_40 t0; - nav__7541_39 t2; - nav__7541_39 t3; - nav__7541_39 const *t4; - uintptr_t t5; - uint8_t *t6; - uint16_t t1; - t0 = fmt_allocPrint__anon_4533__7543(a0, a1); - if (t0.error) { - t1 = t0.error; - t0.payload = (nav__7541_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t0.error = t1; - return t0; - } - t2 = t0.payload; - t3 = t2; - t4 = (nav__7541_39 const *)&t3; - t5 = t2.len; - t5 = t5 - (uintptr_t)1ul; - t2 = (*t4); - t6 = t2.ptr; - t6 = (uint8_t *)(((uintptr_t)t6) + ((uintptr_t)0ul*sizeof(uint8_t))); - t2.ptr = t6; - t2.len = t5; - t0.payload = t2; - t0.error = UINT16_C(0); - return t0; -} - -static void mem_Allocator_free__anon_4508__7542(struct mem_Allocator__565 const a0, nav__7542_40 const a1) { - struct mem_Allocator__565 const *t1; - nav__7542_40 t2; - uintptr_t t3; - uint64_t t4; - uint8_t *t6; - uint8_t *t7; - uint8_t *t8; - uint8_t *const *t9; - struct mem_Allocator__565 t10; - struct mem_Allocator__565 t0; - struct mem_Allocator__565 t12; - struct mem_Allocator_VTable__568 const *const *t13; - struct mem_Allocator_VTable__568 const *t14; - void (*const *t15)(void *, nav__7542_40, uint8_t, uintptr_t); - void (*t16)(void *, nav__7542_40, uint8_t, uintptr_t); - void *t17; - bool t5; - uint8_t t11; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t2 = mem_sliceAsBytes__anon_4540__7544(a1); - t3 = t2.len; - t3 = t3 + (uintptr_t)1ul; - t4 = t3; - t5 = t4 == UINT64_C(0); - if (t5) { - return; - } - goto zig_block_0; - - zig_block_0:; - t6 = t2.ptr; - t7 = (uint8_t *)t6; - t8 = t7; - t9 = (uint8_t *const *)&t8; - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t2.ptr = t7; - t2.len = t3; - t10 = (*t1); - t7 = (*t9); - t7 = (uint8_t *)(((uintptr_t)t7) + ((uintptr_t)0ul*sizeof(uint8_t))); - t2.ptr = t7; - t2.len = t3; - t11 = mem_Alignment_fromByteUnits__1046((uintptr_t)1ul); - t3 = (uintptr_t)zig_return_address(); - t12 = t10; - t1 = (struct mem_Allocator__565 const *)&t12; - t13 = (struct mem_Allocator_VTable__568 const *const *)&t1->vtable; - t14 = (*t13); - t15 = (void (*const *)(void *, nav__7542_40, uint8_t, uintptr_t))&t14->free; - t16 = (*t15); - t17 = t10.ptr; - t16(t17, t2, t11, t3); - return; -} - -static nav__7543_40 fmt_allocPrint__anon_4533__7543(struct mem_Allocator__565 const a0, nav__7543_43 const a1) { - struct mem_Allocator__565 const *t1; - uintptr_t t2; - uintptr_t t6; - uint64_t t3; - nav__7543_54 t4; - struct mem_Allocator__565 t7; - struct mem_Allocator__565 t0; - nav__7543_40 t8; - nav__7543_40 t11; - nav__7543_39 t10; - uint16_t t9; - bool t5; - t0 = a0; - t1 = (struct mem_Allocator__565 const *)&t0; - t3 = fmt_count__anon_4547__7545(a1); - t4 = math_cast__anon_4549__7546(t3); - t5 = t4.is_null != true; - if (t5) { - t6 = t4.payload; - t2 = t6; - goto zig_block_0; - } - return (nav__7543_40){{(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},zig_error_OutOfMemory}; - - zig_block_0:; - t7 = (*t1); - t8 = mem_Allocator_alloc__anon_2153__4103(t7, t2); - if (t8.error) { - t9 = t8.error; - t8.payload = (nav__7543_39){(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul}; - t8.error = t9; - return t8; - } - t10 = t8.payload; - t8 = fmt_bufPrint__anon_4558__7547(t10, a1); - t5 = t8.error == UINT16_C(0); - if (t5) { - t10 = t8.payload; - t8.payload = t10; - t8.error = UINT16_C(0); - t11 = t8; - goto zig_block_1; - } - t9 = t8.error; - switch (t9) { - case zig_error_NoSpaceLeft: { - zig_unreachable(); - } - default: zig_unreachable(); - } - - zig_block_1:; - return t11; -} - -static nav__7544_39 mem_sliceAsBytes__anon_4540__7544(nav__7544_39 const a0) { - uintptr_t t0; - uint64_t t1; - uint8_t *t3; - uint8_t *t4; - uint8_t *t5; - uint8_t *const *t6; - nav__7544_39 t7; - bool t2; - t0 = a0.len; - t1 = t0; - t2 = t1 == UINT64_C(0); - if (t2) { - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - t3 = a0.ptr; - t4 = (uint8_t *)t3; - t5 = t4; - t6 = (uint8_t *const *)&t5; - t0 = a0.len; - t4 = (*t6); - t4 = (uint8_t *)(((uintptr_t)t4) + ((uintptr_t)0ul*sizeof(uint8_t))); - t7.ptr = t4; - t7.len = t0; - return t7; -} - -static uint16_t fmt_format__anon_4615__7586(struct io_Writer__3920 const a0, nav__7586_40 const a1) { - struct io_Writer__3920 const *t1; - struct io_Writer__3920 t2; - struct io_Writer__3920 t0; - uint8_t const *t4; - uint16_t t3; - t0 = a0; - t1 = (struct io_Writer__3920 const *)&t0; - t2 = (*t1); - t3 = io_Writer_writeAll__7060(t2, (nav__7586_44){(uint8_t const *)&__anon_4667,(uintptr_t)10ul}); - if (t3) { - return t3; - } - t4 = a1.f0; - t3 = fmt_formatType__anon_4940__7754(t4, (struct fmt_FormatOptions__4926){{(uintptr_t)0xaaaaaaaaaaaaaaaaul,true},{(uintptr_t)0xaaaaaaaaaaaaaaaaul,true},UINT32_C(32),UINT8_C(2)}, a0, (uintptr_t)3ul); - if (t3) { - return t3; - } - t2 = (*t1); - t3 = io_Writer_writeAll__7060(t2, (nav__7586_44){(uint8_t const *)&__anon_4948,(uintptr_t)1ul}); - if (t3) { - return t3; - } - t4 = a1.f1; - t3 = fmt_formatType__anon_4940__7754(t4, (struct fmt_FormatOptions__4926){{(uintptr_t)0xaaaaaaaaaaaaaaaaul,true},{(uintptr_t)0xaaaaaaaaaaaaaaaaul,true},UINT32_C(32),UINT8_C(2)}, a0, (uintptr_t)3ul); - if (t3) { - return t3; - } - t2 = (*t1); - t3 = io_Writer_writeAll__7060(t2, (nav__7586_44){(uint8_t const *)&__anon_4968,(uintptr_t)1ul}); - if (t3) { - return t3; - } - return 0; -} - -static uint64_t fmt_count__anon_4547__7545(nav__7545_39 const a0) { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 t1; - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 t0; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 t2; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 t3; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 const *t4; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 const *t5; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 const *const *t6; - void const **t8; - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *t9; - void const *t10; - nav__7545_53 (**t11)(void const *, nav__7545_54); - struct io_Writer__3920 t12; - struct io_Writer__3920 t7; - uint64_t t15; - uint16_t t13; - bool t14; - t1 = io_counting_writer_countingWriter__anon_4579__7572(); - t0 = t1; - t2 = io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_writer__7571(&t0); - t3 = t2; - t4 = (struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 const *)&t3; - t5 = t4; - t6 = (struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 const *const *)&t5; - t8 = (void const **)&t7.context; - t4 = (*t6); - t9 = (struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *)&t4->context; - t10 = (void const *)t9; - (*t8) = t10; - t11 = (nav__7545_53 (**)(void const *, nav__7545_54))&t7.writeFn; - (*t11) = &io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWr__7585; - t12 = t7; - t13 = fmt_format__anon_4615__7586(t12, a0); - t14 = t13 == UINT16_C(0); - if (t14) { - goto zig_block_0; - } - zig_unreachable(); - - zig_block_0:; - t1 = t0; - t15 = t1.bytes_written; - return t15; -} - -static nav__7546_38 math_cast__anon_4549__7546(uint64_t const a0) { - uintptr_t t0; - nav__7546_38 t1; - t0 = a0; - t1.is_null = false; - t1.payload = t0; - return t1; -} - -static nav__7547_40 fmt_bufPrint__anon_4558__7547(nav__7547_39 const a0, nav__7547_42 const a1) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t1; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t0; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 t2; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 t3; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 const *t4; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 const *t5; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 const *const *t6; - void const **t8; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t9; - void const *t10; - nav__7547_57 (**t11)(void const *, nav__7547_58); - struct io_Writer__3920 t12; - struct io_Writer__3920 t7; - nav__7547_39 t15; - nav__7547_40 t16; - uint16_t t13; - bool t14; - t1 = io_fixed_buffer_stream_fixedBufferStream__anon_2181__4136(a0); - t0 = t1; - t2 = io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_writer__4126(&t0); - t3 = t2; - t4 = (struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 const *)&t3; - t5 = t4; - t6 = (struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 const *const *)&t5; - t8 = (void const **)&t7.context; - t4 = (*t6); - t9 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t4->context; - t10 = (void const *)t9; - (*t8) = t10; - t11 = (nav__7547_57 (**)(void const *, nav__7547_58))&t7.writeFn; - (*t11) = &io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write__7767; - t12 = t7; - t13 = fmt_format__anon_4615__7586(t12, a1); - t14 = t13 == UINT16_C(0); - if (t14) { - goto zig_block_0; - } - switch (t13) { - case zig_error_NoSpaceLeft: { - return (nav__7547_40){{(uint8_t *)(uintptr_t)0xaaaaaaaaaaaaaaaaul, (uintptr_t)0xaaaaaaaaaaaaaaaaul},zig_error_NoSpaceLeft}; - } - default: { - zig_unreachable(); - } - } - - zig_block_0:; - t1 = t0; - t15 = io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_getWritten__4134(t1); - t16.payload = t15; - t16.error = UINT16_C(0); - return t16; -} - -static struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 io_counting_writer_countingWriter__anon_4579__7572(void) { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 t0; - t0 = (struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576){UINT64_C(0)}; - return t0; -} - -static struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_writer__7571(struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const a0) { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 **t1; - struct io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_2cerror_7b_7d_2c_28function_20_27write_27_29_29__4596 t0; - t1 = (struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 **)&t0.context; - (*t1) = a0; - return t0; -} - -static nav__7585_38 io_GenericWriter_28_2aio_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWr__7585(void const *const a0, nav__7585_41 const a1) { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *t0; - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *t1; - nav__7585_38 t2; - nav__7585_38 t3; - t0 = (struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *)a0; - t1 = (*t0); - t2 = io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_write__7570(t1, a1); - memcpy(&t3, &t2, sizeof(nav__7585_38)); - return t3; -} - -static uint16_t fmt_formatType__anon_4940__7754(uint8_t const *const a0, struct fmt_FormatOptions__4926 const a1, struct io_Writer__3920 const a2, uintptr_t const a3) { - nav__7754_47 t2; - nav__7754_47 t3; - uint8_t const *t0; - struct io_Writer__3920 t1; - uint16_t t4; - uint16_t t5; - (void)a3; - t0 = a0; - t1 = a2; - t2 = mem_span__anon_4156__7165(a0); - memcpy(&t3, &t2, sizeof(nav__7754_47)); - t4 = fmt_formatBuf__anon_5040__7768(t3, a1, a2); - memcpy(&t5, &t4, sizeof(uint16_t)); - return t5; -} - -static struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_writer__4126(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const a0) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 **t1; - struct io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write_27_29_29__4984 t0; - t1 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 **)&t0.context; - (*t1) = a0; - return t0; -} - -static nav__7767_38 io_GenericWriter_28_2aio_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_2cerror_7bNoSpaceLeft_7d_2c_28function_20_27write__7767(void const *const a0, nav__7767_41 const a1) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t0; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t1; - nav__7767_38 t2; - nav__7767_38 t3; - t0 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)a0; - t1 = (*t0); - t2 = io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_write__4129(t1, a1); - memcpy(&t3, &t2, sizeof(nav__7767_38)); - return t3; -} - -static nav__4134_39 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_getWritten__4134(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 const a0) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 const *t1; - nav__4134_39 const *t2; - uintptr_t t3; - nav__4134_39 t4; - uint8_t *t5; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 t0; - t0 = a0; - t1 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 const *)&t0; - t2 = (nav__4134_39 const *)&t1->buffer; - t3 = a0.pos; - t4 = (*t2); - t5 = t4.ptr; - t5 = (uint8_t *)(((uintptr_t)t5) + ((uintptr_t)0ul*sizeof(uint8_t))); - t4.ptr = t5; - t4.len = t3; - return t4; -} - -static nav__7570_38 io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29_write__7570(struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const a0, nav__7570_42 const a1) { - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *t1; - nav__7570_38 t2; - uintptr_t t3; - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *t4; - struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *t0; - uint64_t *t5; - uint64_t t6; - uint64_t t7; - t0 = a0; - t1 = (struct io_counting_writer_CountingWriter_28io_GenericWriter_28void_2cerror_7b_7d_2c_28function_20_27dummyWrite_27_29_29_29__4576 *const *)&t0; - t2 = io_dummyWrite__4038(a1); - t3 = t2.payload; - t4 = (*t1); - t5 = (uint64_t *)&t4->bytes_written; - t6 = (*t5); - t7 = t3; - t7 = t6 + t7; - (*t5) = t7; - t2.payload = t3; - t2.error = UINT16_C(0); - return t2; -} - -static nav__7598_38 unicode_utf8ByteSequenceLength__7598(uint8_t const a0) { - nav__7598_38 t0; - switch (a0) { - default: if ((a0 >= UINT8_C(0) && a0 <= UINT8_C(127))) { - t0 = (nav__7598_38){0,UINT8_C(1)}; - goto zig_block_0; - }if ((a0 >= UINT8_C(192) && a0 <= UINT8_C(223))) { - t0 = (nav__7598_38){0,UINT8_C(2)}; - goto zig_block_0; - }if ((a0 >= UINT8_C(224) && a0 <= UINT8_C(239))) { - t0 = (nav__7598_38){0,UINT8_C(3)}; - goto zig_block_0; - }if ((a0 >= UINT8_C(240) && a0 <= UINT8_C(247))) { - t0 = (nav__7598_38){0,UINT8_C(4)}; - goto zig_block_0; - }{ - t0 = (nav__7598_38){zig_error_Utf8InvalidStartByte,UINT8_C(0x2)}; - goto zig_block_0; - } - } - - zig_block_0:; - return t0; -} - -static nav__7614_38 unicode_utf8CountCodepoints__7614(nav__7614_40 const a0) { - nav__7614_40 const *t1; - uintptr_t t4; - uintptr_t t5; - uintptr_t t2; - uintptr_t t3; - uint64_t t6; - uint64_t t7; - nav__7614_40 t9; - nav__7614_40 t0; - uint8_t const *t10; - uint8_t const (*t11)[8]; - nav__7614_38 t16; - nav__7614_50 t17; - nav__7614_48 t14; - uint16_t t15; - bool t8; - uint8_t t12[8]; - uint8_t t13; - t0 = a0; - t1 = (nav__7614_40 const *)&t0; - t2 = (uintptr_t)0ul; - t3 = (uintptr_t)0ul; - zig_loop_9: - t4 = t3; - t5 = a0.len; - t6 = t4; - t7 = t5; - t8 = t6 < t7; - if (t8) { - zig_loop_18: - t5 = t3; - t5 = t5 + (uintptr_t)8ul; - t4 = a0.len; - t7 = t5; - t6 = t4; - t8 = t7 <= t6; - if (t8) { - t4 = t3; - t9 = (*t1); - t10 = t9.ptr; - t10 = (uint8_t const *)(((uintptr_t)t10) + (t4*sizeof(uint8_t))); - t11 = (uint8_t const (*)[8])t10; - memcpy(t12, (const char *)t11, sizeof(uint8_t[8])); - memcpy(&t4, &t12, sizeof(uintptr_t)); - t4 = zig_wrap_u64(t4, UINT8_C(64)); - t4 = t4 & (uintptr_t)9259542123273814144ul; - t6 = t4; - t8 = t6 != UINT64_C(0); - if (t8) { - goto zig_block_2; - } - goto zig_block_4; - - zig_block_4:; - t4 = t2; - t4 = t4 + (uintptr_t)8ul; - t2 = t4; - t4 = t3; - t4 = t4 + (uintptr_t)8ul; - t3 = t4; - goto zig_block_3; - } - goto zig_block_2; - - zig_block_3:; - goto zig_loop_18; - - zig_block_2:; - t5 = t3; - t4 = a0.len; - t7 = t5; - t6 = t4; - t8 = t7 < t6; - if (t8) { - t4 = t3; - t13 = a0.ptr[t4]; - t14 = unicode_utf8ByteSequenceLength__7598(t13); - if (t14.error) { - t15 = t14.error; - t16.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t16.error = t15; - return t16; - } - t13 = t14.payload; - t4 = t3; - t5 = (uintptr_t)t13; - t5 = t4 + t5; - t4 = a0.len; - t6 = t5; - t7 = t4; - t8 = t6 > t7; - if (t8) { - return (nav__7614_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_TruncatedInput}; - } - goto zig_block_6; - - zig_block_6:; - switch (t13) { - case UINT8_C(1): { - goto zig_block_7; - } - default: { - t4 = t3; - t9 = (*t1); - t10 = t9.ptr; - t10 = (uint8_t const *)(((uintptr_t)t10) + (t4*sizeof(uint8_t))); - t4 = (uintptr_t)t13; - t9.ptr = t10; - t9.len = t4; - t17 = unicode_utf8Decode__7604(t9); - if (t17.error) { - t15 = t17.error; - t16.payload = (uintptr_t)0xaaaaaaaaaaaaaaaaul; - t16.error = t15; - return t16; - } - goto zig_block_7; - } - } - - zig_block_7:; - t4 = t3; - t5 = (uintptr_t)t13; - t5 = t4 + t5; - t3 = t5; - t5 = t2; - t5 = t5 + (uintptr_t)1ul; - t2 = t5; - goto zig_block_5; - } - goto zig_block_5; - - zig_block_5:; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_9; - - zig_block_0:; - t5 = t2; - t16.payload = t5; - t16.error = UINT16_C(0); - return t16; -} - -static uint16_t fmt_formatBuf__anon_5040__7768(nav__7768_39 const a0, struct fmt_FormatOptions__4926 const a1, struct io_Writer__3920 const a2) { - struct io_Writer__3920 const *t1; - nav__7768_44 t2; - uintptr_t t4; - uintptr_t t5; - uintptr_t t7; - nav__7768_48 t6; - uint64_t t8; - uint64_t t9; - struct io_Writer__3920 t10; - struct io_Writer__3920 t0; - nav__7768_57 t15; - nav__7768_39 t17; - nav__7768_39 t20; - uint8_t *t19; - uint32_t t14; - uint16_t t11; - uint16_t t12; - nav__7768_60 t16; - bool t3; - uint8_t t18; - uint8_t t13[4]; - t0 = a2; - t1 = (struct io_Writer__3920 const *)&t0; - t2 = a1.width; - t3 = t2.is_null != true; - if (t3) { - t4 = t2.payload; - t6 = unicode_utf8CountCodepoints__7614(a0); - t3 = t6.error == UINT16_C(0); - if (t3) { - t7 = t6.payload; - t5 = t7; - goto zig_block_1; - } - t7 = a0.len; - t5 = t7; - goto zig_block_1; - - zig_block_1:; - t8 = t5; - t9 = t4; - t3 = t8 < t9; - if (t3) { - t5 = t4 - t5; - t7 = t5; - goto zig_block_2; - } - t7 = (uintptr_t)0ul; - goto zig_block_2; - - zig_block_2:; - t9 = t7; - t3 = t9 == UINT64_C(0); - if (t3) { - t10 = (*t1); - t11 = io_Writer_writeAll__7060(t10, a0); - memcpy(&t12, &t11, sizeof(uint16_t)); - return t12; - } - goto zig_block_3; - - zig_block_3:; - t14 = a1.fill; - t15.ptr = &t13[(uintptr_t)0ul]; - t15.len = (uintptr_t)4ul; - t16 = unicode_utf8Encode__7599(t14, t15); - t3 = t16.error == UINT16_C(0); - if (t3) { - t18 = t16.payload; - t19 = (uint8_t *)&t13; - t19 = (uint8_t *)(((uintptr_t)t19) + ((uintptr_t)0ul*sizeof(uint8_t))); - t5 = (uintptr_t)t18; - t15.ptr = t19; - t15.len = t5; - memcpy(&t20, &t15, sizeof(nav__7768_39)); - t17 = t20; - goto zig_block_4; - - } - t12 = t16.error; - switch (t12) { - case zig_error_Utf8CannotEncodeSurrogateHalf: - case zig_error_CodepointTooLarge: { - t17 = (nav__7768_39){(uint8_t const *)&__anon_5138,(uintptr_t)3ul}; - goto zig_block_4; - } - default: zig_unreachable(); - } - - zig_block_4:; - t18 = a1.alignment; - switch (t18) { - case UINT8_C(0): { - t10 = (*t1); - t12 = io_Writer_writeAll__7060(t10, a0); - if (t12) { - return t12; - } - t10 = (*t1); - t12 = io_Writer_writeBytesNTimes__7064(t10, t17, t7); - if (t12) { - return t12; - } - goto zig_block_6; - } - case UINT8_C(1): { - t5 = t7 / (uintptr_t)2ul; - t7 = t7 + (uintptr_t)1ul; - t7 = t7 / (uintptr_t)2ul; - t10 = (*t1); - t12 = io_Writer_writeBytesNTimes__7064(t10, t17, t5); - if (t12) { - return t12; - } - t10 = (*t1); - t12 = io_Writer_writeAll__7060(t10, a0); - if (t12) { - return t12; - } - t10 = (*t1); - t12 = io_Writer_writeBytesNTimes__7064(t10, t17, t7); - if (t12) { - return t12; - } - goto zig_block_6; - } - case UINT8_C(2): { - t10 = (*t1); - t12 = io_Writer_writeBytesNTimes__7064(t10, t17, t7); - if (t12) { - return t12; - } - t10 = (*t1); - t12 = io_Writer_writeAll__7060(t10, a0); - if (t12) { - return t12; - } - goto zig_block_6; - } - default: zig_unreachable(); - } - - zig_block_6:; - goto zig_block_0; - } - t10 = (*t1); - t12 = io_Writer_writeAll__7060(t10, a0); - if (t12) { - return t12; - } - goto zig_block_0; - - zig_block_0:; - return 0; -} - -static nav__4129_38 io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29_write__4129(struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const a0, nav__4129_42 const a1) { - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *t1; - nav__4129_42 const *t3; - uintptr_t t4; - uintptr_t t10; - uint64_t t5; - uint64_t t11; - uintptr_t *t7; - nav__4129_50 *t8; - nav__4129_50 t9; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t12; - struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *t0; - uint8_t *t13; - nav__4129_42 t14; - nav__4129_42 t2; - uint8_t const *t15; - nav__4129_38 t16; - bool t6; - t0 = a0; - t1 = (struct io_fixed_buffer_stream_FixedBufferStream_28_5b_5du8_29__2178 *const *)&t0; - t2 = a1; - t3 = (nav__4129_42 const *)&t2; - t4 = a1.len; - t5 = t4; - t6 = t5 == UINT64_C(0); - if (t6) { - return (nav__4129_38){(uintptr_t)0ul,0}; - } - goto zig_block_0; - - zig_block_0:; - t7 = (uintptr_t *)&a0->pos; - t4 = (*t7); - t8 = (nav__4129_50 *)&a0->buffer; - t9 = (*t8); - t10 = t9.len; - t5 = t4; - t11 = t10; - t6 = t5 >= t11; - if (t6) { - return (nav__4129_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NoSpaceLeft}; - } - goto zig_block_1; - - zig_block_1:; - t8 = (nav__4129_50 *)&a0->buffer; - t9 = (*t8); - t10 = t9.len; - t7 = (uintptr_t *)&a0->pos; - t4 = (*t7); - t4 = t10 - t4; - t10 = a1.len; - t10 = (t4 < t10) ? t4 : t10; - t11 = t10; - t12 = (*t1); - t8 = (nav__4129_50 *)&t12->buffer; - t7 = (uintptr_t *)&a0->pos; - t10 = (*t7); - t9 = (*t8); - t13 = t9.ptr; - t13 = (uint8_t *)(((uintptr_t)t13) + (t10*sizeof(uint8_t))); - t10 = t11; - t9.ptr = t13; - t9.len = t10; - t14 = (*t3); - t15 = t14.ptr; - t15 = (uint8_t const *)(((uintptr_t)t15) + ((uintptr_t)0ul*sizeof(uint8_t))); - t10 = t11; - t14.ptr = t15; - t14.len = t10; - t15 = t14.ptr; - if (t9.len != 0) memcpy(t9.ptr, t15, t9.len * sizeof(uint8_t)); - t12 = (*t1); - t7 = (uintptr_t *)&t12->pos; - t10 = (*t7); - t4 = t11; - t4 = t10 + t4; - (*t7) = t4; - t6 = t11 == UINT64_C(0); - if (t6) { - return (nav__4129_38){(uintptr_t)0xaaaaaaaaaaaaaaaaul,zig_error_NoSpaceLeft}; - } - goto zig_block_2; - - zig_block_2:; - t4 = t11; - t16.payload = t4; - t16.error = UINT16_C(0); - return t16; -} - -static nav__4038_38 io_dummyWrite__4038(nav__4038_40 const a0) { - uintptr_t t0; - nav__4038_38 t1; - t0 = a0.len; - t1.payload = t0; - t1.error = UINT16_C(0); - return t1; -} - -static nav__7604_38 unicode_utf8Decode__7604(nav__7604_40 const a0) { - nav__7604_40 const *t1; - uintptr_t t2; - nav__7604_40 t7; - nav__7604_40 t0; - uint8_t const *t8; - uint8_t const (*t9)[2]; - uint8_t const (*t13)[3]; - uint8_t const (*t16)[4]; - nav__7604_38 t3; - nav__7604_38 t6; - nav__7604_38 t12; - uint32_t t5; - uint8_t t4; - uint8_t t10[2]; - nav__7604_48 t11; - uint8_t t14[3]; - nav__7604_52 t15; - uint8_t t17[4]; - nav__7604_56 t18; - t0 = a0; - t1 = (nav__7604_40 const *)&t0; - t2 = a0.len; - switch (t2) { - case (uintptr_t)1ul: { - t4 = a0.ptr[(uintptr_t)0ul]; - t5 = (uint32_t)t4; - t6.payload = t5; - t6.error = UINT16_C(0); - t3 = t6; - goto zig_block_0; - } - case (uintptr_t)2ul: { - t7 = (*t1); - t8 = t7.ptr; - t8 = (uint8_t const *)(((uintptr_t)t8) + ((uintptr_t)0ul*sizeof(uint8_t))); - t9 = (uint8_t const (*)[2])t8; - memcpy(t10, (const char *)t9, sizeof(uint8_t[2])); - memcpy(t11.array, t10, sizeof(nav__7604_48)); - t6 = unicode_utf8Decode2__7606(t11); - memcpy(&t12, &t6, sizeof(nav__7604_38)); - t3 = t12; - goto zig_block_0; - } - case (uintptr_t)3ul: { - t7 = (*t1); - t8 = t7.ptr; - t8 = (uint8_t const *)(((uintptr_t)t8) + ((uintptr_t)0ul*sizeof(uint8_t))); - t13 = (uint8_t const (*)[3])t8; - memcpy(t14, (const char *)t13, sizeof(uint8_t[3])); - memcpy(t15.array, t14, sizeof(nav__7604_52)); - t12 = unicode_utf8Decode3__7608(t15); - memcpy(&t6, &t12, sizeof(nav__7604_38)); - t3 = t6; - goto zig_block_0; - } - case (uintptr_t)4ul: { - t7 = (*t1); - t8 = t7.ptr; - t8 = (uint8_t const *)(((uintptr_t)t8) + ((uintptr_t)0ul*sizeof(uint8_t))); - t16 = (uint8_t const (*)[4])t8; - memcpy(t17, (const char *)t16, sizeof(uint8_t[4])); - memcpy(t18.array, t17, sizeof(nav__7604_56)); - t12 = unicode_utf8Decode4__7612(t18); - memcpy(&t6, &t12, sizeof(nav__7604_38)); - t3 = t6; - goto zig_block_0; - } - default: { - zig_unreachable(); - } - } - - zig_block_0:; - return t3; -} - -static nav__7597_38 unicode_utf8CodepointSequenceLength__7597(uint32_t const a0) { - bool t0; - t0 = a0 < UINT32_C(128); - if (t0) { - return (nav__7597_38){0,UINT8_C(1)}; - } - goto zig_block_0; - - zig_block_0:; - t0 = a0 < UINT32_C(2048); - if (t0) { - return (nav__7597_38){0,UINT8_C(2)}; - } - goto zig_block_1; - - zig_block_1:; - t0 = a0 < UINT32_C(65536); - if (t0) { - return (nav__7597_38){0,UINT8_C(3)}; - } - goto zig_block_2; - - zig_block_2:; - t0 = a0 < UINT32_C(1114112); - if (t0) { - return (nav__7597_38){0,UINT8_C(4)}; - } - goto zig_block_3; - - zig_block_3:; - return (nav__7597_38){zig_error_CodepointTooLarge,UINT8_C(0x2)}; -} - -static nav__7769_38 unicode_utf8EncodeImpl__anon_5170__7769(uint32_t const a0, nav__7769_40 const a1) { - nav__7769_40 const *t1; - uintptr_t t5; - uint64_t t6; - uint64_t t7; - nav__7769_40 t9; - nav__7769_40 t0; - uint8_t *t10; - uint32_t t12; - nav__7769_38 t2; - uint16_t t3; - uint8_t t4; - uint8_t t11; - bool t8; - t0 = a1; - t1 = (nav__7769_40 const *)&t0; - t2 = unicode_utf8CodepointSequenceLength__7597(a0); - if (t2.error) { - t3 = t2.error; - t2.payload = UINT8_C(0x2); - t2.error = t3; - return t2; - } - t4 = t2.payload; - t5 = a1.len; - t6 = t5; - t7 = (uint64_t)t4; - t8 = t6 >= t7; - debug_assert__180(t8); - switch (t4) { - case UINT8_C(1): { - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)0ul]; - t11 = (uint8_t)a0; - (*t10) = t11; - goto zig_block_0; - } - case UINT8_C(2): { - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)0ul]; - t12 = zig_shr_u32(a0, UINT8_C(6)); - t12 = UINT32_C(192) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)1ul]; - t12 = a0 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - goto zig_block_0; - } - case UINT8_C(3): { - t8 = unicode_isSurrogateCodepoint__7677(a0); - if (t8) { - return (nav__7769_38){zig_error_Utf8CannotEncodeSurrogateHalf,UINT8_C(0x2)}; - } - goto zig_block_1; - - zig_block_1:; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)0ul]; - t12 = zig_shr_u32(a0, UINT8_C(12)); - t12 = UINT32_C(224) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)1ul]; - t12 = zig_shr_u32(a0, UINT8_C(6)); - t12 = t12 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)2ul]; - t12 = a0 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - goto zig_block_0; - } - case UINT8_C(4): { - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)0ul]; - t12 = zig_shr_u32(a0, UINT8_C(18)); - t12 = UINT32_C(240) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)1ul]; - t12 = zig_shr_u32(a0, UINT8_C(12)); - t12 = t12 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)2ul]; - t12 = zig_shr_u32(a0, UINT8_C(6)); - t12 = t12 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - t9 = (*t1); - t10 = &t9.ptr[(uintptr_t)3ul]; - t12 = a0 & UINT32_C(63); - t12 = UINT32_C(128) | t12; - t11 = (uint8_t)t12; - (*t10) = t11; - goto zig_block_0; - } - default: { - zig_unreachable(); - } - } - - zig_block_0:; - t2.payload = t4; - t2.error = UINT16_C(0); - return t2; -} - -static nav__7599_38 unicode_utf8Encode__7599(uint32_t const a0, nav__7599_40 const a1) { - nav__7599_38 t0; - nav__7599_38 t1; - t0 = unicode_utf8EncodeImpl__anon_5170__7769(a0, a1); - memcpy(&t1, &t0, sizeof(nav__7599_38)); - return t1; -} - -static uint16_t io_Writer_writeBytesNTimes__7064(struct io_Writer__3920 const a0, nav__7064_40 const a1, uintptr_t const a2) { - struct io_Writer__3920 const *t1; - uintptr_t t3; - uintptr_t t2; - uint64_t t4; - uint64_t t5; - struct io_Writer__3920 t7; - struct io_Writer__3920 t0; - uint16_t t8; - bool t6; - t0 = a0; - t1 = (struct io_Writer__3920 const *)&t0; - t2 = (uintptr_t)0ul; - zig_loop_9: - t3 = t2; - t4 = t3; - t5 = a2; - t6 = t4 < t5; - if (t6) { - t7 = (*t1); - t8 = io_Writer_writeAll__7060(t7, a1); - if (t8) { - return t8; - } - t3 = t2; - t3 = t3 + (uintptr_t)1ul; - t2 = t3; - goto zig_block_1; - } - goto zig_block_0; - - zig_block_1:; - goto zig_loop_9; - - zig_block_0:; - return 0; -} - -static nav__7606_38 unicode_utf8Decode2__7606(nav__7606_40 const a0) { - uint32_t t3; - uint32_t t4; - uint32_t t2; - nav__7606_38 t5; - uint8_t t0; - bool t1; - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(224); - t1 = t0 == UINT8_C(192); - debug_assert__180(t1); - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(31); - t3 = (uint32_t)t0; - t2 = t3; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7606_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_0; - - zig_block_0:; - t3 = t2; - t3 = zig_shlw_u32(t3, UINT8_C(6), UINT8_C(21)); - t2 = t3; - t3 = t2; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(63); - t4 = (uint32_t)t0; - t4 = t3 | t4; - t2 = t4; - t4 = t2; - t1 = t4 < UINT32_C(128); - if (t1) { - return (nav__7606_38){UINT32_C(0xaaaaa),zig_error_Utf8OverlongEncoding}; - } - goto zig_block_1; - - zig_block_1:; - t4 = t2; - t5.payload = t4; - t5.error = UINT16_C(0); - return t5; -} - -static nav__7608_38 unicode_utf8Decode3__7608(nav__7608_40 const a0) { - nav__7608_38 t1; - uint32_t t3; - uint16_t t2; - nav__7608_40 t0; - bool t4; - bool t5; - memcpy(t0.array, a0.array, sizeof(nav__7608_40)); - t1 = unicode_utf8Decode3AllowSurrogateHalf__7610(t0); - if (t1.error) { - t2 = t1.error; - t1.payload = UINT32_C(0xaaaaa); - t1.error = t2; - return t1; - } - t3 = t1.payload; - t4 = UINT32_C(55296) <= t3; - if (t4) { - t4 = t3 <= UINT32_C(57343); - t5 = t4; - goto zig_block_1; - } - t5 = false; - goto zig_block_1; - - zig_block_1:; - if (t5) { - return (nav__7608_38){UINT32_C(0xaaaaa),zig_error_Utf8EncodesSurrogateHalf}; - } - goto zig_block_0; - - zig_block_0:; - t1.payload = t3; - t1.error = UINT16_C(0); - return t1; -} - -static nav__7612_38 unicode_utf8Decode4__7612(nav__7612_40 const a0) { - uint32_t t3; - uint32_t t4; - uint32_t t2; - nav__7612_38 t5; - uint8_t t0; - bool t1; - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(248); - t1 = t0 == UINT8_C(240); - debug_assert__180(t1); - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(7); - t3 = (uint32_t)t0; - t2 = t3; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7612_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_0; - - zig_block_0:; - t3 = t2; - t3 = zig_shlw_u32(t3, UINT8_C(6), UINT8_C(21)); - t2 = t3; - t3 = t2; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(63); - t4 = (uint32_t)t0; - t4 = t3 | t4; - t2 = t4; - t0 = a0.array[(uintptr_t)2ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7612_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_1; - - zig_block_1:; - t4 = t2; - t4 = zig_shlw_u32(t4, UINT8_C(6), UINT8_C(21)); - t2 = t4; - t4 = t2; - t0 = a0.array[(uintptr_t)2ul]; - t0 = t0 & UINT8_C(63); - t3 = (uint32_t)t0; - t3 = t4 | t3; - t2 = t3; - t0 = a0.array[(uintptr_t)3ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7612_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_2; - - zig_block_2:; - t3 = t2; - t3 = zig_shlw_u32(t3, UINT8_C(6), UINT8_C(21)); - t2 = t3; - t3 = t2; - t0 = a0.array[(uintptr_t)3ul]; - t0 = t0 & UINT8_C(63); - t4 = (uint32_t)t0; - t4 = t3 | t4; - t2 = t4; - t4 = t2; - t1 = t4 < UINT32_C(65536); - if (t1) { - return (nav__7612_38){UINT32_C(0xaaaaa),zig_error_Utf8OverlongEncoding}; - } - goto zig_block_3; - - zig_block_3:; - t4 = t2; - t1 = t4 > UINT32_C(1114111); - if (t1) { - return (nav__7612_38){UINT32_C(0xaaaaa),zig_error_Utf8CodepointTooLarge}; - } - goto zig_block_4; - - zig_block_4:; - t4 = t2; - t5.payload = t4; - t5.error = UINT16_C(0); - return t5; -} - -static bool unicode_isSurrogateCodepoint__7677(uint32_t const a0) { - bool t0; - switch (a0) { - default: if ((a0 >= UINT32_C(55296) && a0 <= UINT32_C(57343))) { - t0 = true; - goto zig_block_0; - }{ - t0 = false; - goto zig_block_0; - } - } - - zig_block_0:; - return t0; -} - -static nav__7610_38 unicode_utf8Decode3AllowSurrogateHalf__7610(nav__7610_40 const a0) { - uint32_t t3; - uint32_t t4; - uint32_t t2; - nav__7610_38 t5; - uint8_t t0; - bool t1; - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(240); - t1 = t0 == UINT8_C(224); - debug_assert__180(t1); - t0 = a0.array[(uintptr_t)0ul]; - t0 = t0 & UINT8_C(15); - t3 = (uint32_t)t0; - t2 = t3; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7610_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_0; - - zig_block_0:; - t3 = t2; - t3 = zig_shlw_u32(t3, UINT8_C(6), UINT8_C(21)); - t2 = t3; - t3 = t2; - t0 = a0.array[(uintptr_t)1ul]; - t0 = t0 & UINT8_C(63); - t4 = (uint32_t)t0; - t4 = t3 | t4; - t2 = t4; - t0 = a0.array[(uintptr_t)2ul]; - t0 = t0 & UINT8_C(192); - t1 = t0 != UINT8_C(128); - if (t1) { - return (nav__7610_38){UINT32_C(0xaaaaa),zig_error_Utf8ExpectedContinuation}; - } - goto zig_block_1; - - zig_block_1:; - t4 = t2; - t4 = zig_shlw_u32(t4, UINT8_C(6), UINT8_C(21)); - t2 = t4; - t4 = t2; - t0 = a0.array[(uintptr_t)2ul]; - t0 = t0 & UINT8_C(63); - t3 = (uint32_t)t0; - t3 = t4 | t3; - t2 = t3; - t3 = t2; - t1 = t3 < UINT32_C(2048); - if (t1) { - return (nav__7610_38){UINT32_C(0xaaaaa),zig_error_Utf8OverlongEncoding}; - } - goto zig_block_2; - - zig_block_2:; - t3 = t2; - t5.payload = t3; - t5.error = UINT16_C(0); - return t5; -} - -static uint16_t instruments_perf_PerfInstrument_add_marker__759(struct instruments_perf_PerfInstrument__559 *const a0, uint32_t const a1, struct shared_MarkerType__1953 const a2) { - struct instruments_perf_PerfInstrument__559 *const *t1; - struct instruments_perf_PerfInstrument__559 *t2; - struct instruments_perf_PerfInstrument__559 *t0; - struct fifo_UnixPipe_Writer__600 *t3; - struct shared_Command__struct_1951__1951 t4; - struct shared_Command__1946 t5; - struct fifo_UnixPipe_Reader__602 *t7; - uint16_t t6; - t0 = a0; - t1 = (struct instruments_perf_PerfInstrument__559 *const *)&t0; - t2 = (*t1); - t3 = (struct fifo_UnixPipe_Writer__600 *)&t2->writer; - t4.marker = a2; - t4.pid = a1; - t5.tag = UINT8_C(7); - t5.payload.AddMarker = t4; - t6 = fifo_UnixPipe_Writer_sendCmd__1080(t3, t5); - if (t6) { - return t6; - } - t2 = (*t1); - t7 = (struct fifo_UnixPipe_Reader__602 *)&t2->reader; - t6 = fifo_UnixPipe_Reader_waitForAck__1087(t7, (nav__759_72){UINT64_C(0xaaaaaaaaaaaaaaaa),true}); - if (t6) { - return t6; - } - return 0; -} - -uint8_t c_instrument_hooks_add_marker__251(struct instruments_root_InstrumentHooks__547 *const a0, uint32_t const a1, uint8_t const a2, uint64_t const a3) { - struct instruments_root_InstrumentHooks__547 *t1; - struct instruments_root_InstrumentHooks__547 *t2; - struct instruments_root_InstrumentHooks__547 *t7; - struct instruments_root_InstrumentHooks__547 *const *t3; - struct shared_MarkerType__1953 t4; - struct shared_MarkerType__1953 t5; - struct instruments_root_InstrumentHooks__547 t8; - struct instruments_perf_PerfInstrument__559 *t10; - uint16_t t6; - uint16_t t11; - uint16_t t12; - bool t0; - uint8_t t9; - t0 = a0 != NULL; - if (t0) { - t1 = a0; - t2 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t2; - switch (a2) { - case UINT8_C(0): { - t5.tag = UINT8_C(0); - t5.payload.SampleStart = a3; - t4 = t5; - goto zig_block_1; - } - case UINT8_C(1): { - t5.tag = UINT8_C(1); - t5.payload.SampleEnd = a3; - t4 = t5; - goto zig_block_1; - } - case UINT8_C(2): { - t5.tag = UINT8_C(2); - t5.payload.BenchmarkStart = a3; - t4 = t5; - goto zig_block_1; - } - case UINT8_C(3): { - t5.tag = UINT8_C(3); - t5.payload.BenchmarkEnd = a3; - t4 = t5; - goto zig_block_1; - } - default: { - return UINT8_C(2); - } - } - - zig_block_1:; - t1 = (*t3); - t7 = t1; - t3 = (struct instruments_root_InstrumentHooks__547 *const *)&t7; - t8 = (*t1); - t9 = t8.tag; - t0 = t9 == UINT8_C(1); - if (t0) { - t1 = (*t3); - t10 = (struct instruments_perf_PerfInstrument__559 *)&t1->payload.perf; - t11 = instruments_perf_PerfInstrument_add_marker__759(t10, a1, t4); - memcpy(&t12, &t11, sizeof(uint16_t)); - t6 = t12; - goto zig_block_3; - } - goto zig_block_4; - - zig_block_4:; - t6 = 0; - goto zig_block_3; - - zig_block_3:; - memcpy(&t12, &t6, sizeof(uint16_t)); - t0 = t12 == UINT16_C(0); - if (t0) { - goto zig_block_2; - } - return UINT8_C(1); - - zig_block_2:; - goto zig_block_0; - } - goto zig_block_0; - - zig_block_0:; - return UINT8_C(0); -} - -uint64_t c_instrument_hooks_current_timestamp__252(void) { - uint64_t t0; - t0 = utils_clock_gettime_monotonic__3834(); - return t0; -} - -static uint64_t utils_clock_gettime_monotonic__3834(void) { - struct os_linux_timespec__struct_2922__2922 t0; - struct os_linux_timespec__struct_2922__2922 t3; - nav__3834_41 t1; - intptr_t t4; - uint64_t t5; - uint64_t t6; - bool t2; - t1 = posix_clock_gettime__1633(UINT32_C(1)); - t2 = t1.error == UINT16_C(0); - if (t2) { - t3 = t1.payload; - t0 = t3; - goto zig_block_0; - } - zig_unreachable(); - - zig_block_0:; - t4 = t0.sec; - t5 = (uint64_t)t4; - t5 = t5 * UINT64_C(1000000000); - t4 = t0.nsec; - t6 = (uint64_t)t4; - t6 = t5 + t6; - return t6; -} - -static uint64_t const builtin_zig_backend__257 = UINT64_C(3); - -static bool const start_simplified_logic__109 = false; - -static uint8_t const builtin_output_mode__258 = UINT8_C(1); - -static uint8_t const builtin_link_mode__259 = UINT8_C(0); - -static uint64_t features_features__324 = ((uint64_t)UINT64_C(0)); - -static uintptr_t const bit_set_IntegerBitSet_2864_29_bit_length__355 = 64ul; - -static bool const builtin_link_libc__269 = true; - -static bool const posix_use_libc__1285 = true; - -static struct Target_Os__625 const builtin_os__265 = {{ .linux = {{{6ul,16ul,7ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}},{6ul,16ul,7ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}}},{2ul,39ul,0ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}},UINT32_C(14)} },UINT8_C(9)}; - -static uint8_t const c_native_os__1727 = UINT8_C(9); - -static struct Target_DynamicLinker__800 const Target_DynamicLinker_none__3449 = {"\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252",UINT8_C(0)}; - -static bool const builtin_is_test__261 = false; - -static uint8_t *heap_CAllocator_alloc__3573(void *const a0, uintptr_t const a1, uint8_t const a2, uintptr_t const a3) { - uint64_t t0; - uint8_t *t2; - bool t1; - (void)a0; - (void)a3; - t0 = a1; - t1 = t0 > UINT64_C(0); - debug_assert__180(t1); - t2 = heap_CAllocator_alignedAlloc__3570(a1, a2); - return t2; -} - -static bool heap_CAllocator_resize__3574(void *const a0, nav__3574_40 const a1, uint8_t const a2, uintptr_t const a3, uintptr_t const a4) { - uintptr_t t0; - uint64_t t1; - uint64_t t2; - uint8_t *t4; - bool t3; - (void)a0; - (void)a2; - (void)a4; - t0 = a1.len; - t1 = a3; - t2 = t0; - t3 = t1 <= t2; - if (t3) { - return true; - } - goto zig_block_0; - - zig_block_0:; - t4 = a1.ptr; - t0 = heap_CAllocator_alignedAllocSize__3572(t4); - t2 = a3; - t1 = t0; - t3 = t2 <= t1; - if (t3) { - return true; - } - goto zig_block_1; - - zig_block_1:; - return false; -} - -static uint8_t *heap_CAllocator_remap__3575(void *const a0, nav__3575_40 const a1, uint8_t const a2, uintptr_t const a3, uintptr_t const a4) { - uint8_t *t0; - uint8_t *t2; - uint8_t *t3; - bool t1; - t1 = heap_CAllocator_resize__3574(a0, a1, a2, a3, a4); - if (t1) { - t2 = a1.ptr; - t3 = (uint8_t *)t2; - t0 = t3; - goto zig_block_0; - } - t0 = NULL; - goto zig_block_0; - - zig_block_0:; - return t0; -} - -static void heap_CAllocator_free__3576(void *const a0, nav__3576_40 const a1, uint8_t const a2, uintptr_t const a3) { - uint8_t *t0; - (void)a0; - (void)a2; - (void)a3; - t0 = a1.ptr; - heap_CAllocator_alignedFree__3571(t0); - return; -} - -static uint8_t *heap_CAllocator_alignedAlloc__3570(uintptr_t const a0, uint8_t const a1) { - uint8_t const *t1; - uintptr_t t3; - uint64_t t4; - void *t9; - void *t5; - uint8_t *t10; - int t6; - int32_t t7; - uint8_t t2; - uint8_t t0; - bool t8; - t0 = a1; - t1 = (uint8_t const *)&t0; - t2 = (*t1); - t3 = mem_Alignment_toByteUnits__1045(t2); - t3 = ((uintptr_t)8ul > t3) ? (uintptr_t)8ul : t3; - t4 = t3; - t3 = t4; - t6 = posix_memalign(&t5, t3, a0); - t7 = t6; - t8 = t7 != INT32_C(0); - if (t8) { - return NULL; - } - goto zig_block_0; - - zig_block_0:; - t9 = t5; - t10 = (uint8_t *)t9; - return t10; -} - -static uintptr_t heap_CAllocator_alignedAllocSize__3572(uint8_t *const a0) { - void const *t0; - void const *t1; - uintptr_t t2; - t0 = (void const *)a0; - t1 = t0; - t2 = malloc_usable_size(t1); - return t2; -} - -static void heap_CAllocator_alignedFree__3571(uint8_t *const a0) { - void *t0; - void *t1; - t0 = (void *)a0; - t1 = t0; - free(t1); - return; -} - -static uintptr_t mem_Alignment_toByteUnits__1045(uint8_t const a0) { - uintptr_t t1; - uint8_t t0; - t0 = a0; - t1 = zig_shlw_u64((uintptr_t)1ul, t0, UINT8_C(64)); - return t1; -} - -static struct mem_Allocator__565 const heap_c_allocator__3538 = {((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}; - -static struct mem_Allocator__565 const c_allocator__236 = {((void *)(uintptr_t)0xaaaaaaaaaaaaaaaaul),((struct mem_Allocator_VTable__568 const *)&heap_CAllocator_vtable__3565)}; - -static struct Target_Cpu_Feature_Set__817 const Target_Cpu_Feature_Set_empty__3494 = {{0ul,0ul,0ul,0ul,0ul}}; - -static struct Target_Cpu__785 const builtin_cpu__264 = {((struct Target_Cpu_Model__812 const *)&Target_x86_cpu_alderlake__3597),{{9528139926881771760ul,4854352088661217417ul,15258802296178673304ul,3ul,0ul}},UINT8_C(42)}; - -static uint8_t const builtin_abi__263 = UINT8_C(1); - -static uint8_t const builtin_object_format__267 = UINT8_C(0); - -static struct Target__623 const builtin_target__266 = {{((struct Target_Cpu_Model__812 const *)&Target_x86_cpu_alderlake__3597),{{9528139926881771760ul,4854352088661217417ul,15258802296178673304ul,3ul,0ul}},UINT8_C(42)},{{ .linux = {{{6ul,16ul,7ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}},{6ul,16ul,7ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}}},{2ul,39ul,0ul,{NULL,0xaaaaaaaaaaaaaaaaul},{NULL,0xaaaaaaaaaaaaaaaaul}},UINT32_C(14)} },UINT8_C(9)},UINT8_C(1),UINT8_C(0),{"/nix/store/zdpby3l6azi78sl83cpad2qjpfj25aqx-glibc-2.40-66/lib/ld-linux-x86-64.so.2\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252\252",UINT8_C(82)}}; - -static struct builtin_CallingConvention__266 const builtin_CallingConvention_c__465 = {{ .x86_64_sysv = {{UINT64_C(0xaaaaaaaaaaaaaaaa),true}} },UINT8_C(4)}; - -static uint8_t const (*const shared_RUNNER_CTL_FIFO__3701)[21] = &__anon_1845; - -static uint8_t const (*const shared_RUNNER_ACK_FIFO__3702)[21] = &__anon_1916; - -static uint64_t const c_PROTOCOL_VERSION__237 = UINT64_C(1); - -static uint8_t const mem_native_endian__769 = UINT8_C(1); - -static int const cimport_F_GETFL__5129 = 3; - -static int const cimport_O_NONBLOCK__5105 = 2048; - -static int const cimport_F_SETFL__5130 = 4; - -static uint8_t const os_linux_native_arch__2633 = UINT8_C(42); - -static int const cimport_EINTR__6758 = 4; - -static uint8_t const fs_path_native_os__4243 = UINT8_C(9); - -static uint8_t const fs_native_os__1097 = UINT8_C(9); - -static uint8_t const fs_Dir_native_os__3825 = UINT8_C(9); - -static bool const fs_File_is_windows__1273 = false; - -static uint8_t const posix_native_os__1283 = UINT8_C(9); - -static uint8_t const builtin_mode__268 = UINT8_C(3); - -static bool const debug_runtime_safety__159 = false; - -static bool const fs_Dir_have_flock__3826 = true; - -static uint8_t const c_native_abi__1725 = UINT8_C(1); - -static bool const posix_unexpected_error_tracing__1714 = false; - -static bool const posix_lfs64_abi__1713 = true; - -static bool const mem_backend_supports_vectors__797 = true; - -static bool const builtin_valgrind_support__272 = false; - -static bool const debug_default_enable_segfault_handler__205 = false; - -static uint8_t const log_default_level__7302 = UINT8_C(0); - -static struct std_Options__4269 const std_options__97 = {{0xaaaaaaaaaaaaaaaaul,true},{0xaaaaaaaaaaaaaaaaul,true},3ul,false,UINT8_C(0),false,true,false,false,false,UINT8_C(2)}; - -static nav__3554_38 const heap_page_size_min_default__3554 = {4096ul,false}; - -static uintptr_t const heap_page_size_min__3533 = 4096ul; - -static uint16_t const fmt_max_format_args__7370 = UINT16_C(32); - -static uint8_t const (*const fmt_ANY__7373)[4] = &__anon_5013; - -static uint8_t const unicode_native_endian__7595 = UINT8_C(1); - -static uint32_t const unicode_replacement_character__7596 = UINT32_C(65533); - -static uint8_t const c_MARKER_TYPE_SAMPLE_START__247 = UINT8_C(0); - -static uint8_t const c_MARKER_TYPE_SAMPLE_END__248 = UINT8_C(1); - -static uint8_t const c_MARKER_TYPE_BENCHMARK_START__249 = UINT8_C(2); - -static uint8_t const c_MARKER_TYPE_BENCHMARK_END__250 = UINT8_C(3); - -static struct mem_Allocator_VTable__568 const heap_CAllocator_vtable__3565 = {&heap_CAllocator_alloc__3573,&heap_CAllocator_resize__3574,&heap_CAllocator_remap__3575,&heap_CAllocator_free__3576}; - -static bool const heap_CAllocator_supports_malloc_size__3566 = true; - -static bool const heap_CAllocator_supports_posix_memalign__3568 = true; - -static struct Target_Cpu_Model__812 const Target_x86_cpu_alderlake__3597 = {{(uint8_t const *)&__anon_5291,9ul},{(uint8_t const *)&__anon_5291,9ul},{{9516916112185360560ul,4872366487170699401ul,11223533324467504792ul,3ul,0ul}}}; - -#endif -#ifndef WRAPPER_H -#define WRAPPER_H - -#include - -#ifndef _WIN32 -#include "callgrind.h" -#include "valgrind.h" - -uint8_t running_on_valgrind() { return RUNNING_ON_VALGRIND > 0; } - -void callgrind_dump_stats() { CALLGRIND_DUMP_STATS; } - -void callgrind_dump_stats_at(uint8_t const* pos_str) { - CALLGRIND_DUMP_STATS_AT(pos_str); -} - -void callgrind_zero_stats() { CALLGRIND_ZERO_STATS; } - -void callgrind_start_instrumentation() { CALLGRIND_START_INSTRUMENTATION; } - -void callgrind_stop_instrumentation() { CALLGRIND_STOP_INSTRUMENTATION; } - -#else -// Windows and other platforms - provide no-op implementations -uint8_t running_on_valgrind() { return 0; } - -void callgrind_dump_stats() {} - -void callgrind_dump_stats_at(uint8_t const* pos_str) {} - -void callgrind_zero_stats() {} - -void callgrind_start_instrumentation() {} - -void callgrind_stop_instrumentation() {} -#endif - -#endif diff --git a/testing/capi/instrument-hooks/includes/callgrind.h b/testing/capi/instrument-hooks/includes/callgrind.h deleted file mode 100644 index 589b020f..00000000 --- a/testing/capi/instrument-hooks/includes/callgrind.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (callgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of callgrind, a valgrind tool for cache simulation - and call tree tracing. - - Copyright (C) 2003-2017 Josef Weidendorfer. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (callgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - -#ifndef __CALLGRIND_H -#define __CALLGRIND_H - -#include "valgrind.h" - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE ORDER OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end. - - The identification ('C','T') for Callgrind has historical - reasons: it was called "Calltree" before. Besides, ('C','G') would - clash with cachegrind. - */ - -typedef enum { - VG_USERREQ__DUMP_STATS = VG_USERREQ_TOOL_BASE('C', 'T'), - VG_USERREQ__ZERO_STATS, - VG_USERREQ__TOGGLE_COLLECT, - VG_USERREQ__DUMP_STATS_AT, - VG_USERREQ__START_INSTRUMENTATION, - VG_USERREQ__STOP_INSTRUMENTATION -} Vg_CallgrindClientRequest; - -/* Dump current state of cost centers, and zero them afterwards */ -#define CALLGRIND_DUMP_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS, 0, 0, 0, 0, 0) - -/* Dump current state of cost centers, and zero them afterwards. - The argument is appended to a string stating the reason which triggered - the dump. This string is written as a description field into the - profile data dump. */ -#define CALLGRIND_DUMP_STATS_AT(pos_str) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DUMP_STATS_AT, pos_str, 0, 0, 0, \ - 0) - -/* Zero cost centers */ -#define CALLGRIND_ZERO_STATS \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__ZERO_STATS, 0, 0, 0, 0, 0) - -/* Toggles collection state. - The collection state specifies whether the happening of events - should be noted or if they are to be ignored. Events are noted - by increment of counters in a cost center */ -#define CALLGRIND_TOGGLE_COLLECT \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__TOGGLE_COLLECT, 0, 0, 0, 0, 0) - -/* Start full callgrind instrumentation if not already switched on. - When cache simulation is done, it will flush the simulated cache; - this will lead to an artificial cache warmup phase afterwards with - cache misses which would not have happened in reality. */ -#define CALLGRIND_START_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__START_INSTRUMENTATION, 0, 0, 0, \ - 0, 0) - -/* Stop full callgrind instrumentation if not already switched off. - This flushes Valgrinds translation cache, and does no additional - instrumentation afterwards, which effectivly will run at the same - speed as the "none" tool (ie. at minimal slowdown). - Use this to bypass Callgrind aggregation for uninteresting code parts. - To start Callgrind in this mode to ignore the setup phase, use - the option "--instr-atstart=no". */ -#define CALLGRIND_STOP_INSTRUMENTATION \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STOP_INSTRUMENTATION, 0, 0, 0, \ - 0, 0) - -#endif /* __CALLGRIND_H */ diff --git a/testing/capi/instrument-hooks/includes/core.h b/testing/capi/instrument-hooks/includes/core.h deleted file mode 100644 index 29b1b618..00000000 --- a/testing/capi/instrument-hooks/includes/core.h +++ /dev/null @@ -1,86 +0,0 @@ -// This file was manually created and exposes the functions of this library. -// TODO: Can we automatically generate this file? - -#ifndef CORE_H -#define CORE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _WIN32 -#include "callgrind.h" -#include "valgrind.h" -#else -#define CALLGRIND_START_INSTRUMENTATION -#define CALLGRIND_STOP_INSTRUMENTATION -#define CALLGRIND_ZERO_STATS -#endif - -typedef uint64_t *InstrumentHooks; - -InstrumentHooks *instrument_hooks_init(void); -void instrument_hooks_deinit(InstrumentHooks *); - -bool instrument_hooks_is_instrumented(InstrumentHooks *); -uint8_t instrument_hooks_start_benchmark(InstrumentHooks *); -uint8_t instrument_hooks_stop_benchmark(InstrumentHooks *); -uint8_t instrument_hooks_set_executed_benchmark(InstrumentHooks *, int32_t pid, - const char *uri); -// Deprecated: use instrument_hooks_set_executed_benchmark instead -uint8_t instrument_hooks_executed_benchmark(InstrumentHooks *, int32_t pid, - const char *uri); -uint8_t instrument_hooks_set_integration(InstrumentHooks *, const char *name, - const char *version); - -#define MARKER_TYPE_SAMPLE_START 0 -#define MARKER_TYPE_SAMPLE_END 1 -#define MARKER_TYPE_BENCHMARK_START 2 -#define MARKER_TYPE_BENCHMARK_END 3 - -uint8_t instrument_hooks_add_marker(InstrumentHooks *, uint32_t pid, - uint8_t marker_type, uint64_t timestamp); -uint64_t instrument_hooks_current_timestamp(void); - -void callgrind_start_instrumentation(); -void callgrind_stop_instrumentation(); - -// Feature flags for instrument hooks - -typedef enum { - FEATURE_DISABLE_CALLGRIND_MARKERS = 0, -} instrument_hooks_feature_t; - -void instrument_hooks_set_feature(instrument_hooks_feature_t feature, - bool enabled); - -// Header functions that will be inlined. This can be used by languages that -// directly consume the headers such as C or C++. This will allow for more -// precise tracking of the benchmark performance. - -static inline uint8_t instrument_hooks_start_benchmark_inline( - InstrumentHooks *instance) { - instrument_hooks_set_feature(FEATURE_DISABLE_CALLGRIND_MARKERS, true); - if (instrument_hooks_start_benchmark(instance) != 0) { - return 1; - } - - CALLGRIND_ZERO_STATS; - CALLGRIND_START_INSTRUMENTATION; - return 0; -} - -static inline uint8_t instrument_hooks_stop_benchmark_inline( - InstrumentHooks *instance) { - CALLGRIND_STOP_INSTRUMENTATION; - return instrument_hooks_stop_benchmark(instance); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/testing/capi/instrument-hooks/includes/valgrind.h b/testing/capi/instrument-hooks/includes/valgrind.h deleted file mode 100644 index 7455909c..00000000 --- a/testing/capi/instrument-hooks/includes/valgrind.h +++ /dev/null @@ -1,7168 +0,0 @@ -/* -*- c -*- - ---------------------------------------------------------------- - - Notice that the following BSD-style license applies to this one - file (valgrind.h) only. The rest of Valgrind is licensed under the - terms of the GNU General Public License, version 2, unless - otherwise indicated. See the COPYING file in the source - distribution for details. - - ---------------------------------------------------------------- - - This file is part of Valgrind, a dynamic binary instrumentation - framework. - - Copyright (C) 2000-2017 Julian Seward. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - - 4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - - THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. - - ---------------------------------------------------------------- - - Notice that the above BSD-style license applies to this one file - (valgrind.h) only. The entire rest of Valgrind is licensed under - the terms of the GNU General Public License, version 2. See the - COPYING file in the source distribution for details. - - ---------------------------------------------------------------- -*/ - - -/* This file is for inclusion into client (your!) code. - - You can use these macros to manipulate and query Valgrind's - execution inside your own programs. - - The resulting executables will still run without Valgrind, just a - little bit more slowly than they otherwise would, but otherwise - unchanged. When not running on valgrind, each client request - consumes very few (eg. 7) instructions, so the resulting performance - loss is negligible unless you plan to execute client requests - millions of times per second. Nevertheless, if that is still a - problem, you can compile with the NVALGRIND symbol defined (gcc - -DNVALGRIND) so that client requests are not even compiled in. */ - -#ifndef __VALGRIND_H -#define __VALGRIND_H - - -/* ------------------------------------------------------------------ */ -/* VERSION NUMBER OF VALGRIND */ -/* ------------------------------------------------------------------ */ - -/* Specify Valgrind's version number, so that user code can - conditionally compile based on our version number. Note that these - were introduced at version 3.6 and so do not exist in version 3.5 - or earlier. The recommended way to use them to check for "version - X.Y or later" is (eg) - -#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \ - && (__VALGRIND_MAJOR__ > 3 \ - || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6)) -*/ -#define __VALGRIND_MAJOR__ 3 -#define __VALGRIND_MINOR__ 24 - - -#include - -/* Nb: this file might be included in a file compiled with -ansi. So - we can't use C++ style "//" comments nor the "asm" keyword (instead - use "__asm__"). */ - -/* Derive some tags indicating what the target platform is. Note - that in this file we're using the compiler's CPP symbols for - identifying architectures, which are different to the ones we use - within the rest of Valgrind. Note, __powerpc__ is active for both - 32 and 64-bit PPC, whereas __powerpc64__ is only active for the - latter (on Linux, that is). - - Misc note: how to find out what's predefined in gcc by default: - gcc -Wp,-dM somefile.c -*/ -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_freebsd -#undef PLAT_amd64_freebsd -#undef PLAT_arm64_freebsd -#undef PLAT_x86_win32 -#undef PLAT_amd64_win64 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64be_linux -#undef PLAT_ppc64le_linux -#undef PLAT_arm_linux -#undef PLAT_arm64_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux -#undef PLAT_mips64_linux -#undef PLAT_nanomips_linux -#undef PLAT_x86_solaris -#undef PLAT_amd64_solaris - - -#if defined(__APPLE__) && defined(__i386__) -# define PLAT_x86_darwin 1 -#elif defined(__APPLE__) && defined(__x86_64__) -# define PLAT_amd64_darwin 1 -#elif defined(__FreeBSD__) && defined(__i386__) -# define PLAT_x86_freebsd 1 -#elif defined(__FreeBSD__) && defined(__amd64__) -# define PLAT_amd64_freebsd 1 -#elif defined(__FreeBSD__) && defined(__aarch64__) && !defined(__arm__) -# define PLAT_arm64_freebsd 1 -#elif (defined(__MINGW32__) && defined(__i386__)) \ - || defined(__CYGWIN32__) \ - || (defined(_WIN32) && defined(_M_IX86)) -# define PLAT_x86_win32 1 -#elif (defined(__MINGW32__) && defined(__x86_64__)) \ - || (defined(_WIN32) && defined(_M_X64)) -/* __MINGW32__ and _WIN32 are defined in 64 bit mode as well. */ -# define PLAT_amd64_win64 1 -#elif defined(__linux__) && defined(__i386__) -# define PLAT_x86_linux 1 -#elif defined(__linux__) && defined(__x86_64__) && !defined(__ILP32__) -# define PLAT_amd64_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__) -# define PLAT_ppc32_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF != 2 -/* Big Endian uses ELF version 1 */ -# define PLAT_ppc64be_linux 1 -#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__) && _CALL_ELF == 2 -/* Little Endian uses ELF version 2 */ -# define PLAT_ppc64le_linux 1 -#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__) -# define PLAT_arm_linux 1 -#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__) -# define PLAT_arm64_linux 1 -#elif defined(__linux__) && defined(__s390__) && defined(__s390x__) -# define PLAT_s390x_linux 1 -#elif defined(__linux__) && defined(__mips__) && (__mips==64) -# define PLAT_mips64_linux 1 -#elif defined(__linux__) && defined(__mips__) && (__mips==32) -# define PLAT_mips32_linux 1 -#elif defined(__linux__) && defined(__nanomips__) -# define PLAT_nanomips_linux 1 -#elif defined(__sun) && defined(__i386__) -# define PLAT_x86_solaris 1 -#elif defined(__sun) && defined(__x86_64__) -# define PLAT_amd64_solaris 1 -#else -/* If we're not compiling for our target platform, don't generate - any inline asms. */ -# if !defined(NVALGRIND) -# define NVALGRIND 1 -# endif -#endif - - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ -/* in here of use to end-users -- skip to the next section. */ -/* ------------------------------------------------------------------ */ - -/* - * VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client - * request. Accepts both pointers and integers as arguments. - * - * VALGRIND_DO_CLIENT_REQUEST_STMT(): a statement that invokes a Valgrind - * client request that does not return a value. - - * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind - * client request and whose value equals the client request result. Accepts - * both pointers and integers as arguments. Note that such calls are not - * necessarily pure functions -- they may have side effects. - */ - -#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \ - _zzq_request, _zzq_arg1, _zzq_arg2, \ - _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#define VALGRIND_DO_CLIENT_REQUEST_STMT(_zzq_request, _zzq_arg1, \ - _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - do { (void) VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - (_zzq_request), (_zzq_arg1), (_zzq_arg2), \ - (_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); } while (0) - -#if defined(NVALGRIND) - -/* Define NVALGRIND to completely remove the Valgrind magic sequence - from the compiled code (analogous to NDEBUG's effects on - assert()) */ -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - (_zzq_default) - -#else /* ! NVALGRIND */ - -/* The following defines the magic code sequences which the JITter - spots and handles magically. Don't look too closely at them as - they will rot your brain. - - The assembly code sequences for all architectures is in this one - file. This is because this file must be stand-alone, and we don't - want to have multiple files. - - For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default - value gets put in the return slot, so that everything works when - this is executed not under Valgrind. Args are passed in a memory - block, and so there's no intrinsic limit to the number that could - be passed, but it's currently five. - - The macro args are: - _zzq_rlval result lvalue - _zzq_default default value (result returned when running on real CPU) - _zzq_request request code - _zzq_arg1..5 request params - - The other two macros are used to support function wrapping, and are - a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the - guest's NRADDR pseudo-register and whatever other information is - needed to safely run the call original from the wrapper: on - ppc64-linux, the R2 value at the divert point is also needed. This - information is abstracted into a user-visible type, OrigFn. - - VALGRIND_CALL_NOREDIR_* behaves the same as the following on the - guest, but guarantees that the branch instruction will not be - redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: - branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a - complete inline asm, since it needs to be combined with more magic - inline asm stuff to be useful. -*/ - -/* ----------------- x86-{linux,darwin,solaris} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ - || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ - || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "roll $3, %%edi ; roll $13, %%edi\n\t" \ - "roll $29, %%edi ; roll $19, %%edi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EDX = client_request ( %EAX ) */ \ - "xchgl %%ebx,%%ebx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - "xchgl %%ecx,%%ecx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%EAX */ \ - "xchgl %%edx,%%edx\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "xchgl %%edi,%%edi\n\t" \ - : : : "cc", "memory" \ - ); \ - } while (0) - -#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) - || PLAT_x86_solaris */ - -/* ------------------------- x86-Win32 ------------------------- */ - -#if defined(PLAT_x86_win32) && !defined(__GNUC__) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#if defined(_MSC_VER) - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - __asm rol edi, 3 __asm rol edi, 13 \ - __asm rol edi, 29 __asm rol edi, 19 - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \ - (uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \ - (uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \ - (uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5)) - -static __inline uintptr_t -valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, - uintptr_t _zzq_arg1, uintptr_t _zzq_arg2, - uintptr_t _zzq_arg3, uintptr_t _zzq_arg4, - uintptr_t _zzq_arg5) -{ - volatile uintptr_t _zzq_args[6]; - volatile unsigned int _zzq_result; - _zzq_args[0] = (uintptr_t)(_zzq_request); - _zzq_args[1] = (uintptr_t)(_zzq_arg1); - _zzq_args[2] = (uintptr_t)(_zzq_arg2); - _zzq_args[3] = (uintptr_t)(_zzq_arg3); - _zzq_args[4] = (uintptr_t)(_zzq_arg4); - _zzq_args[5] = (uintptr_t)(_zzq_arg5); - __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default - __SPECIAL_INSTRUCTION_PREAMBLE - /* %EDX = client_request ( %EAX ) */ - __asm xchg ebx,ebx - __asm mov _zzq_result, edx - } - return _zzq_result; -} - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %EAX = guest_NRADDR */ \ - __asm xchg ecx,ecx \ - __asm mov __addr, eax \ - } \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_EAX ERROR - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm { __SPECIAL_INSTRUCTION_PREAMBLE \ - __asm xchg edi,edi \ - } \ - } while (0) - -#else -#error Unsupported compiler. -#endif - -#endif /* PLAT_x86_win32 */ - -/* ----------------- amd64-{linux,darwin,solaris} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ - || defined(PLAT_amd64_solaris) \ - || defined(PLAT_amd64_freebsd) \ - || (defined(PLAT_amd64_win64) && defined(__GNUC__)) - -typedef - struct { - unsigned long int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ - "rolq $61, %%rdi ; rolq $51, %%rdi\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned long int _zzq_args[6]; \ - volatile unsigned long int _zzq_result; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RDX = client_request ( %RAX ) */ \ - "xchgq %%rbx,%%rbx" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), "0" (_zzq_default) \ - : "cc", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %RAX = guest_NRADDR */ \ - "xchgq %%rcx,%%rcx" \ - : "=a" (__addr) \ - : \ - : "cc", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_RAX \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%RAX */ \ - "xchgq %%rdx,%%rdx\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "xchgq %%rdi,%%rdi\n\t" \ - : : : "cc", "memory" \ - ); \ - } while (0) - -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ - -/* ------------------------- amd64-Win64 ------------------------- */ - -#if defined(PLAT_amd64_win64) && !defined(__GNUC__) - -#error Unsupported compiler. - -#endif /* PLAT_amd64_win64 */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rlwinm 0,0,3,0,31 ; rlwinm 0,0,13,0,31\n\t" \ - "rlwinm 0,0,29,0,31 ; rlwinm 0,0,19,0,31\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned int _zzq_args[6]; \ - unsigned int _zzq_result; \ - unsigned int* _zzq_ptr; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or 5,5,5\n\t" \ - ); \ - } while (0) - -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64be_linux) - -typedef - struct { - unsigned long int nraddr; /* where's the code? */ - unsigned long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned long int _zzq_args[6]; \ - unsigned long int _zzq_result; \ - unsigned long int* _zzq_ptr; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R11 */ \ - "or 3,3,3\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or 5,5,5\n\t" \ - ); \ - } while (0) - -#endif /* PLAT_ppc64be_linux */ - -#if defined(PLAT_ppc64le_linux) - -typedef - struct { - unsigned long int nraddr; /* where's the code? */ - unsigned long int r2; /* what tocptr do we need? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ - "rotldi 0,0,61 ; rotldi 0,0,51\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({ unsigned long int _zzq_args[6]; \ - unsigned long int _zzq_result; \ - unsigned long int* _zzq_ptr; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - _zzq_ptr = _zzq_args; \ - __asm__ volatile("mr 3,%1\n\t" /*default*/ \ - "mr 4,%2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = client_request ( %R4 ) */ \ - "or 1,1,1\n\t" \ - "mr %0,3" /*result*/ \ - : "=b" (_zzq_result) \ - : "b" (_zzq_default), "b" (_zzq_ptr) \ - : "cc", "memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR */ \ - "or 2,2,2\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %R3 = guest_NRADDR_GPR2 */ \ - "or 4,4,4\n\t" \ - "mr %0,3" \ - : "=b" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->r2 = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R12 */ \ - "or 3,3,3\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or 5,5,5\n\t" \ - ); \ - } while (0) - -#endif /* PLAT_ppc64le_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \ - "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("mov r3, %1\n\t" /*default*/ \ - "mov r4, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = client_request ( R4 ) */ \ - "orr r10, r10, r10\n\t" \ - "mov %0, r3" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "cc","memory", "r3", "r4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* R3 = guest_NRADDR */ \ - "orr r11, r11, r11\n\t" \ - "mov %0, r3" \ - : "=r" (__addr) \ - : \ - : "cc", "memory", "r3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir *%R4 */ \ - "orr r12, r12, r12\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "orr r9, r9, r9\n\t" \ - : : : "cc", "memory" \ - ); \ - } while (0) - -#endif /* PLAT_arm_linux */ - -/* ------------------------ arm64-{linux,freebsd} ------------------------- */ - -#if defined(PLAT_arm64_linux) || defined(PLAT_arm64_freebsd) - -typedef - struct { - unsigned long int nraddr; /* where's the code? */ - } - OrigFn; - -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "ror x12, x12, #3 ; ror x12, x12, #13 \n\t" \ - "ror x12, x12, #51 ; ror x12, x12, #61 \n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - \ - __extension__ \ - ({volatile unsigned long int _zzq_args[6]; \ - volatile unsigned long int _zzq_result; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - __asm__ volatile("mov x3, %1\n\t" /*default*/ \ - "mov x4, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* X3 = client_request ( X4 ) */ \ - "orr x10, x10, x10\n\t" \ - "mov %0, x3" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" ((unsigned long int)(_zzq_default)), \ - "r" (&_zzq_args[0]) \ - : "cc","memory", "x3", "x4"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* X3 = guest_NRADDR */ \ - "orr x11, x11, x11\n\t" \ - "mov %0, x3" \ - : "=r" (__addr) \ - : \ - : "cc", "memory", "x3" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* branch-and-link-to-noredir X8 */ \ - "orr x12, x12, x12\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "orr x9, x9, x9\n\t" \ - : : : "cc", "memory" \ - ); \ - } while (0) - -#endif /* PLAT_arm64_linux || PLAT_arm64_freebsd */ - -/* ------------------------ s390x-linux ------------------------ */ - -#if defined(PLAT_s390x_linux) - -typedef - struct { - unsigned long int nraddr; /* where's the code? */ - } - OrigFn; - -/* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specific - * code. This detection is implemented in platform specific toIR.c - * (e.g. VEX/priv/guest_s390_decoder.c). - */ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "lr 15,15\n\t" \ - "lr 1,1\n\t" \ - "lr 2,2\n\t" \ - "lr 3,3\n\t" - -#define __CLIENT_REQUEST_CODE "lr 2,2\n\t" -#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t" -#define __CALL_NO_REDIR_CODE "lr 4,4\n\t" -#define __VEX_INJECT_IR_CODE "lr 5,5\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({volatile unsigned long int _zzq_args[6]; \ - volatile unsigned long int _zzq_result; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - __asm__ volatile(/* r2 = args */ \ - "lgr 2,%1\n\t" \ - /* r3 = default */ \ - "lgr 3,%2\n\t" \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CLIENT_REQUEST_CODE \ - /* results = r3 */ \ - "lgr %0, 3\n\t" \ - : "=d" (_zzq_result) \ - : "a" (&_zzq_args[0]), \ - "0" ((unsigned long int)_zzq_default) \ - : "cc", "2", "3", "memory" \ - ); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - __GET_NR_CONTEXT_CODE \ - "lgr %0, 3\n\t" \ - : "=a" (__addr) \ - : \ - : "cc", "3", "memory" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_R1 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - __CALL_NO_REDIR_CODE - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - __VEX_INJECT_IR_CODE); \ - } while (0) - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips32-linux ---------------- */ - -#if defined(PLAT_mips32_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; - -/* .word 0x342 - * .word 0x742 - * .word 0xC2 - * .word 0x4C2*/ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "srl $0, $0, 13\n\t" \ - "srl $0, $0, 29\n\t" \ - "srl $0, $0, 3\n\t" \ - "srl $0, $0, 19\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("move $11, %1\n\t" /*default*/ \ - "move $12, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* T3 = client_request ( T4 ) */ \ - "or $13, $13, $13\n\t" \ - "move %0, $11\n\t" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "$11", "$12", "memory"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* %t9 = guest_NRADDR */ \ - "or $14, $14, $14\n\t" \ - "move %0, $11" /*result*/ \ - : "=r" (__addr) \ - : \ - : "$11" \ - ); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_T9 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir *%t9 */ \ - "or $15, $15, $15\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or $11, $11, $11\n\t" \ - ); \ - } while (0) - - -#endif /* PLAT_mips32_linux */ - -/* ------------------------- mips64-linux ---------------- */ - -#if defined(PLAT_mips64_linux) - -typedef - struct { - unsigned long nraddr; /* where's the code? */ - } - OrigFn; - -/* dsll $0,$0, 3 - * dsll $0,$0, 13 - * dsll $0,$0, 29 - * dsll $0,$0, 19*/ -#define __SPECIAL_INSTRUCTION_PREAMBLE \ - "dsll $0,$0, 3 ; dsll $0,$0,13\n\t" \ - "dsll $0,$0,29 ; dsll $0,$0,19\n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned long int _zzq_args[6]; \ - volatile unsigned long int _zzq_result; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ - __asm__ volatile("move $11, %1\n\t" /*default*/ \ - "move $12, %2\n\t" /*ptr*/ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* $11 = client_request ( $12 ) */ \ - "or $13, $13, $13\n\t" \ - "move %0, $11\n\t" /*result*/ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "$11", "$12", "memory"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* $11 = guest_NRADDR */ \ - "or $14, $14, $14\n\t" \ - "move %0, $11" /*result*/ \ - : "=r" (__addr) \ - : \ - : "$11"); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_T9 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir $25 */ \ - "or $15, $15, $15\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or $11, $11, $11\n\t" \ - ); \ - } while (0) - -#endif /* PLAT_mips64_linux */ - -#if defined(PLAT_nanomips_linux) - -typedef - struct { - unsigned int nraddr; /* where's the code? */ - } - OrigFn; -/* - 8000 c04d srl zero, zero, 13 - 8000 c05d srl zero, zero, 29 - 8000 c043 srl zero, zero, 3 - 8000 c053 srl zero, zero, 19 -*/ - -#define __SPECIAL_INSTRUCTION_PREAMBLE "srl[32] $zero, $zero, 13 \n\t" \ - "srl[32] $zero, $zero, 29 \n\t" \ - "srl[32] $zero, $zero, 3 \n\t" \ - "srl[32] $zero, $zero, 19 \n\t" - -#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - _zzq_default, _zzq_request, \ - _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ - __extension__ \ - ({ volatile unsigned int _zzq_args[6]; \ - volatile unsigned int _zzq_result; \ - _zzq_args[0] = (unsigned int)(_zzq_request); \ - _zzq_args[1] = (unsigned int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned int)(_zzq_arg5); \ - __asm__ volatile("move $a7, %1\n\t" /* default */ \ - "move $t0, %2\n\t" /* ptr */ \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* $a7 = client_request( $t0 ) */ \ - "or[32] $t0, $t0, $t0\n\t" \ - "move %0, $a7\n\t" /* result */ \ - : "=r" (_zzq_result) \ - : "r" (_zzq_default), "r" (&_zzq_args[0]) \ - : "$a7", "$t0", "memory"); \ - _zzq_result; \ - }) - -#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ - { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ - volatile unsigned long int __addr; \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - /* $a7 = guest_NRADDR */ \ - "or[32] $t1, $t1, $t1\n\t" \ - "move %0, $a7" /*result*/ \ - : "=r" (__addr) \ - : \ - : "$a7"); \ - _zzq_orig->nraddr = __addr; \ - } - -#define VALGRIND_CALL_NOREDIR_T9 \ - __SPECIAL_INSTRUCTION_PREAMBLE \ - /* call-noredir $25 */ \ - "or[32] $t2, $t2, $t2\n\t" - -#define VALGRIND_VEX_INJECT_IR() \ - do { \ - __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ - "or[32] $t3, $t3, $t3\n\t" \ - ); \ - } while (0) - -#endif -/* Insert assembly code for other platforms here... */ - -#endif /* NVALGRIND */ - - -/* ------------------------------------------------------------------ */ -/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ -/* ugly. It's the least-worst tradeoff I can think of. */ -/* ------------------------------------------------------------------ */ - -/* This section defines magic (a.k.a appalling-hack) macros for doing - guaranteed-no-redirection macros, so as to get from function - wrappers to the functions they are wrapping. The whole point is to - construct standard call sequences, but to do the call itself with a - special no-redirect call pseudo-instruction that the JIT - understands and handles specially. This section is long and - repetitious, and I can't see a way to make it shorter. - - The naming scheme is as follows: - - CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc} - - 'W' stands for "word" and 'v' for "void". Hence there are - different macros for calling arity 0, 1, 2, 3, 4, etc, functions, - and for each, the possibility of returning a word-typed result, or - no result. -*/ - -/* Use these to write the name of your wrapper. NOTE: duplicates - VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. NOTE also: inserts - the default behaviour equivalance class tag "0000" into the name. - See pub_tool_redir.h for details -- normally you don't need to - think about this, though. */ - -/* Use an extra level of macroisation so as to ensure the soname/fnname - args are fully macro-expanded before pasting them together. */ -#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd - -#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgw00000ZU_,soname,_,fnname) - -#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgw00000ZZ_,soname,_,fnname) - -/* Use this macro from within a wrapper function to collect the - context (address and possibly other info) of the original function. - Once you have that you can then use it in one of the CALL_FN_ - macros. The type of the argument _lval is OrigFn. */ -#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) - -/* Also provide end-user facilities for function replacement, rather - than wrapping. A replacement function differs from a wrapper in - that it has no way to get hold of the original function being - called, and hence no way to call onwards to it. In a replacement - function, VALGRIND_GET_ORIG_FN always returns zero. */ - -#define I_REPLACE_SONAME_FNNAME_ZU(soname,fnname) \ - VG_CONCAT4(_vgr00000ZU_,soname,_,fnname) - -#define I_REPLACE_SONAME_FNNAME_ZZ(soname,fnname) \ - VG_CONCAT4(_vgr00000ZZ_,soname,_,fnname) - -/* Derivatives of the main macros below, for calling functions - returning void. */ - -#define CALL_FN_v_v(fnptr) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_v(_junk,fnptr); } while (0) - -#define CALL_FN_v_W(fnptr, arg1) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_W(_junk,fnptr,arg1); } while (0) - -#define CALL_FN_v_WW(fnptr, arg1,arg2) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) - -#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) - -#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0) - -#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0) - -#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0) - -#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \ - do { volatile unsigned long _junk; \ - CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0) - -/* ----------------- x86-{linux,darwin,solaris} ---------------- */ - -#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ - || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) - -/* These regs are trashed by the hidden call. No need to mention eax - as gcc can already see that, plus causes gcc to bomb. */ -#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movl %%esp,%%edi\n\t" \ - "andl $0xfffffff0,%%esp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movl %%edi,%%esp\n\t" - -/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $12, %%esp\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $8, %%esp\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "subl $4, %%esp\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "pushl 48(%%eax)\n\t" \ - "pushl 44(%%eax)\n\t" \ - "pushl 40(%%eax)\n\t" \ - "pushl 36(%%eax)\n\t" \ - "pushl 32(%%eax)\n\t" \ - "pushl 28(%%eax)\n\t" \ - "pushl 24(%%eax)\n\t" \ - "pushl 20(%%eax)\n\t" \ - "pushl 16(%%eax)\n\t" \ - "pushl 12(%%eax)\n\t" \ - "pushl 8(%%eax)\n\t" \ - "pushl 4(%%eax)\n\t" \ - "movl (%%eax), %%eax\n\t" /* target->%eax */ \ - VALGRIND_CALL_NOREDIR_EAX \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "edi" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */ - -/* ---------------- amd64-{linux,darwin,solaris} --------------- */ - -#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ - || defined(PLAT_amd64_solaris) || defined(PLAT_amd64_freebsd) - -/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ - "rdi", "r8", "r9", "r10", "r11" - -/* This is all pretty complex. It's so as to make stack unwinding - work reliably. See bug 243270. The basic problem is the sub and - add of 128 of %rsp in all of the following macros. If gcc believes - the CFA is in %rsp, then unwinding may fail, because what's at the - CFA is not what gcc "expected" when it constructs the CFIs for the - places where the macros are instantiated. - - But we can't just add a CFI annotation to increase the CFA offset - by 128, to match the sub of 128 from %rsp, because we don't know - whether gcc has chosen %rsp as the CFA at that point, or whether it - has chosen some other register (eg, %rbp). In the latter case, - adding a CFI annotation to change the CFA offset is simply wrong. - - So the solution is to get hold of the CFA using - __builtin_dwarf_cfa(), put it in a known register, and add a - CFI annotation to say what the register is. We choose %rbp for - this (perhaps perversely), because: - - (1) %rbp is already subject to unwinding. If a new register was - chosen then the unwinder would have to unwind it in all stack - traces, which is expensive, and - - (2) %rbp is already subject to precise exception updates in the - JIT. If a new register was chosen, we'd have to have precise - exceptions for it too, which reduces performance of the - generated code. - - However .. one extra complication. We can't just whack the result - of __builtin_dwarf_cfa() into %rbp and then add %rbp to the - list of trashed registers at the end of the inline assembly - fragments; gcc won't allow %rbp to appear in that list. Hence - instead we need to stash %rbp in %r15 for the duration of the asm, - and say that %r15 is trashed instead. gcc seems happy to go with - that. - - Oh .. and this all needs to be conditionalised so that it is - unchanged from before this commit, when compiled with older gccs - that don't support __builtin_dwarf_cfa. Furthermore, since - this header file is freestanding, it has to be independent of - config.h, and so the following conditionalisation cannot depend on - configure time checks. - - Although it's not clear from - 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)', - this expression excludes Darwin. - .cfi directives in Darwin assembly appear to be completely - different and I haven't investigated how they work. - - For even more entertainment value, note we have to use the - completely undocumented __builtin_dwarf_cfa(), which appears to - really compute the CFA, whereas __builtin_frame_address(0) claims - to but actually doesn't. See - https://bugs.kde.org/show_bug.cgi?id=243270#c47 -*/ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"r"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - "movq %%rbp, %%r15\n\t" \ - "movq %2, %%rbp\n\t" \ - ".cfi_remember_state\n\t" \ - ".cfi_def_cfa rbp, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "movq %%r15, %%rbp\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "movq %%rsp,%%r14\n\t" \ - "andq $0xfffffffffffffff0,%%rsp\n\t" -#define VALGRIND_RESTORE_STACK \ - "movq %%r14,%%rsp\n\t" - -/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned - long) == 8. */ - -/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ - macros. In order not to trash the stack redzone, we need to drop - %rsp by 128 before the hidden call, and restore afterwards. The - nastyness is that it is only by luck that the stack still appears - to be unwindable during the hidden call - since then the behaviour - of any routine using this macro does not match what the CFI data - says. Sigh. - - Why is this important? Imagine that a wrapper has a stack - allocated local, and passes to the hidden call, a pointer to it. - Because gcc does not know about the hidden call, it may allocate - that local in the redzone. Unfortunately the hidden call may then - trash it before it comes to use it. So we must step clear of the - redzone, for the duration of the hidden call, to make it safe. - - Probably the same problem afflicts the other redzone-style ABIs too - (ppc64-linux); but for those, the stack is - self describing (none of this CFI nonsense) so at least messing - with the stack pointer doesn't give a danger of non-unwindable - stack. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $136,%%rsp\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - VALGRIND_ALIGN_STACK \ - "subq $128,%%rsp\n\t" \ - "pushq 96(%%rax)\n\t" \ - "pushq 88(%%rax)\n\t" \ - "pushq 80(%%rax)\n\t" \ - "pushq 72(%%rax)\n\t" \ - "pushq 64(%%rax)\n\t" \ - "pushq 56(%%rax)\n\t" \ - "movq 48(%%rax), %%r9\n\t" \ - "movq 40(%%rax), %%r8\n\t" \ - "movq 32(%%rax), %%rcx\n\t" \ - "movq 24(%%rax), %%rdx\n\t" \ - "movq 16(%%rax), %%rsi\n\t" \ - "movq 8(%%rax), %%rdi\n\t" \ - "movq (%%rax), %%rax\n\t" /* target->%rax */ \ - VALGRIND_CALL_NOREDIR_RAX \ - VALGRIND_RESTORE_STACK \ - VALGRIND_CFI_EPILOGUE \ - : /*out*/ "=a" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r14", "r15" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */ - -/* ------------------------ ppc32-linux ------------------------ */ - -#if defined(PLAT_ppc32_linux) - -/* This is useful for finding out about the on-stack stuff: - - extern int f9 ( int,int,int,int,int,int,int,int,int ); - extern int f10 ( int,int,int,int,int,int,int,int,int,int ); - extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); - extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int ); - - int g9 ( void ) { - return f9(11,22,33,44,55,66,77,88,99); - } - int g10 ( void ) { - return f10(11,22,33,44,55,66,77,88,99,110); - } - int g11 ( void ) { - return f11(11,22,33,44,55,66,77,88,99,110,121); - } - int g12 ( void ) { - return f12(11,22,33,44,55,66,77,88,99,110,121,132); - } -*/ - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rlwinm 1,1,0,0,27\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc32-linux, - sizeof(unsigned long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-16\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "addi 1,1,-32\n\t" \ - /* arg12 */ \ - "lwz 3,48(11)\n\t" \ - "stw 3,20(1)\n\t" \ - /* arg11 */ \ - "lwz 3,44(11)\n\t" \ - "stw 3,16(1)\n\t" \ - /* arg10 */ \ - "lwz 3,40(11)\n\t" \ - "stw 3,12(1)\n\t" \ - /* arg9 */ \ - "lwz 3,36(11)\n\t" \ - "stw 3,8(1)\n\t" \ - /* args1-8 */ \ - "lwz 3,4(11)\n\t" /* arg1->r3 */ \ - "lwz 4,8(11)\n\t" \ - "lwz 5,12(11)\n\t" \ - "lwz 6,16(11)\n\t" /* arg4->r6 */ \ - "lwz 7,20(11)\n\t" \ - "lwz 8,24(11)\n\t" \ - "lwz 9,28(11)\n\t" \ - "lwz 10,32(11)\n\t" /* arg8->r10 */ \ - "lwz 11,0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - VALGRIND_RESTORE_STACK \ - "mr %0,3" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc32_linux */ - -/* ------------------------ ppc64-linux ------------------------ */ - -#if defined(PLAT_ppc64be_linux) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rldicr 1,1,0,59\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 11,%1\n\t" \ - "std 2,-16(11)\n\t" /* save tocptr */ \ - "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg12 */ \ - "ld 3,96(11)\n\t" \ - "std 3,136(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(11)\n\t" \ - "std 3,128(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(11)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(11)\n\t" \ - "std 3,112(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(11)\n\t" /* arg1->r3 */ \ - "ld 4, 16(11)\n\t" /* arg2->r4 */ \ - "ld 5, 24(11)\n\t" /* arg3->r5 */ \ - "ld 6, 32(11)\n\t" /* arg4->r6 */ \ - "ld 7, 40(11)\n\t" /* arg5->r7 */ \ - "ld 8, 48(11)\n\t" /* arg6->r8 */ \ - "ld 9, 56(11)\n\t" /* arg7->r9 */ \ - "ld 10, 64(11)\n\t" /* arg8->r10 */ \ - "ld 11, 0(11)\n\t" /* target->r11 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ - "mr 11,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(11)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64be_linux */ - -/* ------------------------- ppc64le-linux ----------------------- */ -#if defined(PLAT_ppc64le_linux) - -/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */ - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "lr", "ctr", "xer", \ - "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \ - "r0", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \ - "r11", "r12", "r13" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -#define VALGRIND_ALIGN_STACK \ - "mr 28,1\n\t" \ - "rldicr 1,1,0,59\n\t" -#define VALGRIND_RESTORE_STACK \ - "mr 1,28\n\t" - -/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned - long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+0]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+1]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+2]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+3]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+4]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+5]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+6]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+7]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+8]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 10, 64(12)\n\t" /* arg8->r10 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+9]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg9 */ \ - "ld 3,72(12)\n\t" \ - "std 3,96(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 10, 64(12)\n\t" /* arg8->r10 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+10]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-128\n\t" /* expand stack frame */ \ - /* arg10 */ \ - "ld 3,80(12)\n\t" \ - "std 3,104(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(12)\n\t" \ - "std 3,96(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 10, 64(12)\n\t" /* arg8->r10 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+11]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg11 */ \ - "ld 3,88(12)\n\t" \ - "std 3,112(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(12)\n\t" \ - "std 3,104(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(12)\n\t" \ - "std 3,96(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 10, 64(12)\n\t" /* arg8->r10 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3+12]; \ - volatile unsigned long _res; \ - /* _argvec[0] holds current r2 across the call */ \ - _argvec[1] = (unsigned long)_orig.r2; \ - _argvec[2] = (unsigned long)_orig.nraddr; \ - _argvec[2+1] = (unsigned long)arg1; \ - _argvec[2+2] = (unsigned long)arg2; \ - _argvec[2+3] = (unsigned long)arg3; \ - _argvec[2+4] = (unsigned long)arg4; \ - _argvec[2+5] = (unsigned long)arg5; \ - _argvec[2+6] = (unsigned long)arg6; \ - _argvec[2+7] = (unsigned long)arg7; \ - _argvec[2+8] = (unsigned long)arg8; \ - _argvec[2+9] = (unsigned long)arg9; \ - _argvec[2+10] = (unsigned long)arg10; \ - _argvec[2+11] = (unsigned long)arg11; \ - _argvec[2+12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "mr 12,%1\n\t" \ - "std 2,-16(12)\n\t" /* save tocptr */ \ - "ld 2,-8(12)\n\t" /* use nraddr's tocptr */ \ - "addi 1,1,-144\n\t" /* expand stack frame */ \ - /* arg12 */ \ - "ld 3,96(12)\n\t" \ - "std 3,120(1)\n\t" \ - /* arg11 */ \ - "ld 3,88(12)\n\t" \ - "std 3,112(1)\n\t" \ - /* arg10 */ \ - "ld 3,80(12)\n\t" \ - "std 3,104(1)\n\t" \ - /* arg9 */ \ - "ld 3,72(12)\n\t" \ - "std 3,96(1)\n\t" \ - /* args1-8 */ \ - "ld 3, 8(12)\n\t" /* arg1->r3 */ \ - "ld 4, 16(12)\n\t" /* arg2->r4 */ \ - "ld 5, 24(12)\n\t" /* arg3->r5 */ \ - "ld 6, 32(12)\n\t" /* arg4->r6 */ \ - "ld 7, 40(12)\n\t" /* arg5->r7 */ \ - "ld 8, 48(12)\n\t" /* arg6->r8 */ \ - "ld 9, 56(12)\n\t" /* arg7->r9 */ \ - "ld 10, 64(12)\n\t" /* arg8->r10 */ \ - "ld 12, 0(12)\n\t" /* target->r12 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R12 \ - "mr 12,%1\n\t" \ - "mr %0,3\n\t" \ - "ld 2,-16(12)\n\t" /* restore tocptr */ \ - VALGRIND_RESTORE_STACK \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[2]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r28" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_ppc64le_linux */ - -/* ------------------------- arm-linux ------------------------- */ - -#if defined(PLAT_arm_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4", "r12", "r14" - -/* Macros to save and align the stack before making a function - call and restore it afterwards as gcc may not keep the stack - pointer aligned if it doesn't realise calls are being made - to other functions. */ - -/* This is a bit tricky. We store the original stack pointer in r10 - as it is callee-saves. gcc doesn't allow the use of r11 for some - reason. Also, we can't directly "bic" the stack pointer in thumb - mode since r13 isn't an allowed register number in that context. - So use r4 as a temporary, since that is about to get trashed - anyway, just after each use of this macro. Side effect is we need - to be very careful about any future changes, since - VALGRIND_ALIGN_STACK simply assumes r4 is usable. */ -#define VALGRIND_ALIGN_STACK \ - "mov r10, sp\n\t" \ - "mov r4, sp\n\t" \ - "bic r4, r4, #7\n\t" \ - "mov sp, r4\n\t" -#define VALGRIND_RESTORE_STACK \ - "mov sp, r10\n\t" - -/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "push {r0, r1, r2, r3} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "push {r0} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #4 \n\t" \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "push {r0, r1} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr r0, [%1, #40] \n\t" \ - "ldr r1, [%1, #44] \n\t" \ - "ldr r2, [%1, #48] \n\t" \ - "push {r0, r1, r2} \n\t" \ - "ldr r0, [%1, #20] \n\t" \ - "ldr r1, [%1, #24] \n\t" \ - "ldr r2, [%1, #28] \n\t" \ - "ldr r3, [%1, #32] \n\t" \ - "ldr r4, [%1, #36] \n\t" \ - "push {r0, r1, r2, r3, r4} \n\t" \ - "ldr r0, [%1, #4] \n\t" \ - "ldr r1, [%1, #8] \n\t" \ - "ldr r2, [%1, #12] \n\t" \ - "ldr r3, [%1, #16] \n\t" \ - "ldr r4, [%1] \n\t" /* target->r4 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \ - VALGRIND_RESTORE_STACK \ - "mov %0, r0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r10" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_arm_linux */ - -/* ------------------------ arm64-linux ------------------------ */ - -#if defined(PLAT_arm64_linux) || defined(PLAT_arm64_freebsd) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS \ - "x0", "x1", "x2", "x3","x4", "x5", "x6", "x7", "x8", "x9", \ - "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", \ - "x18", "x19", "x20", "x30", \ - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \ - "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", \ - "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", \ - "v26", "v27", "v28", "v29", "v30", "v31" - -/* x21 is callee-saved, so we can use it to save and restore SP around - the hidden call. */ -#define VALGRIND_ALIGN_STACK \ - "mov x21, sp\n\t" \ - "bic sp, x21, #15\n\t" -#define VALGRIND_RESTORE_STACK \ - "mov sp, x21\n\t" - -/* These CALL_FN_ macros assume that on arm64-linux, - sizeof(unsigned long) == 8. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x7, [%1, #64] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #0x20 \n\t" \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x7, [%1, #64] \n\t" \ - "ldr x8, [%1, #72] \n\t" \ - "str x8, [sp, #0] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #0x20 \n\t" \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x7, [%1, #64] \n\t" \ - "ldr x8, [%1, #72] \n\t" \ - "str x8, [sp, #0] \n\t" \ - "ldr x8, [%1, #80] \n\t" \ - "str x8, [sp, #8] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #0x30 \n\t" \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x7, [%1, #64] \n\t" \ - "ldr x8, [%1, #72] \n\t" \ - "str x8, [sp, #0] \n\t" \ - "ldr x8, [%1, #80] \n\t" \ - "str x8, [sp, #8] \n\t" \ - "ldr x8, [%1, #88] \n\t" \ - "str x8, [sp, #16] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10,arg11, \ - arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - VALGRIND_ALIGN_STACK \ - "sub sp, sp, #0x30 \n\t" \ - "ldr x0, [%1, #8] \n\t" \ - "ldr x1, [%1, #16] \n\t" \ - "ldr x2, [%1, #24] \n\t" \ - "ldr x3, [%1, #32] \n\t" \ - "ldr x4, [%1, #40] \n\t" \ - "ldr x5, [%1, #48] \n\t" \ - "ldr x6, [%1, #56] \n\t" \ - "ldr x7, [%1, #64] \n\t" \ - "ldr x8, [%1, #72] \n\t" \ - "str x8, [sp, #0] \n\t" \ - "ldr x8, [%1, #80] \n\t" \ - "str x8, [sp, #8] \n\t" \ - "ldr x8, [%1, #88] \n\t" \ - "str x8, [sp, #16] \n\t" \ - "ldr x8, [%1, #96] \n\t" \ - "str x8, [sp, #24] \n\t" \ - "ldr x8, [%1] \n\t" /* target->x8 */ \ - VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_X8 \ - VALGRIND_RESTORE_STACK \ - "mov %0, x0" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "x21" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_arm64_linux */ - -/* ------------------------- s390x-linux ------------------------- */ - -#if defined(PLAT_s390x_linux) - -/* Similar workaround as amd64 (see above), but we use r11 as frame - pointer and save the old r11 in r7. r11 might be used for - argvec, therefore we copy argvec in r1 since r1 is clobbered - after the call anyway. */ -#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM) -# define __FRAME_POINTER \ - ,"d"(__builtin_dwarf_cfa()) -# define VALGRIND_CFI_PROLOGUE \ - ".cfi_remember_state\n\t" \ - "lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \ - "lgr 7,11\n\t" \ - "lgr 11,%2\n\t" \ - ".cfi_def_cfa 11, 0\n\t" -# define VALGRIND_CFI_EPILOGUE \ - "lgr 11, 7\n\t" \ - ".cfi_restore_state\n\t" -#else -# define __FRAME_POINTER -# define VALGRIND_CFI_PROLOGUE \ - "lgr 1,%1\n\t" -# define VALGRIND_CFI_EPILOGUE -#endif - -/* Nb: On s390 the stack pointer is properly aligned *at all times* - according to the s390 GCC maintainer. (The ABI specification is not - precise in this regard.) Therefore, VALGRIND_ALIGN_STACK and - VALGRIND_RESTORE_STACK are not defined here. */ - -/* These regs are trashed by the hidden call. Note that we overwrite - r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the - function a proper return address. All others are ABI defined call - clobbers. */ -#if defined(__VX__) || defined(__S390_VX__) -#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \ - "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \ - "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \ - "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" -#else -#define __CALLER_SAVED_REGS "0", "1", "2", "3", "4", "5", "14", \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" -#endif - -/* Nb: Although r11 is modified in the asm snippets below (inside - VALGRIND_CFI_PROLOGUE) it is not listed in the clobber section, for - two reasons: - (1) r11 is restored in VALGRIND_CFI_EPILOGUE, so effectively it is not - modified - (2) GCC will complain that r11 cannot appear inside a clobber section, - when compiled with -O -fno-omit-frame-pointer - */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 1, 0(1)\n\t" /* target->r1 */ \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -/* The call abi has the arguments in r2-r6 and stack */ -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1, arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-160\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,160\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-168\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,168\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-176\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,176\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-184\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,184\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-192\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,192\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-200\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,200\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-208\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,208\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \ - arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)arg1; \ - _argvec[2] = (unsigned long)arg2; \ - _argvec[3] = (unsigned long)arg3; \ - _argvec[4] = (unsigned long)arg4; \ - _argvec[5] = (unsigned long)arg5; \ - _argvec[6] = (unsigned long)arg6; \ - _argvec[7] = (unsigned long)arg7; \ - _argvec[8] = (unsigned long)arg8; \ - _argvec[9] = (unsigned long)arg9; \ - _argvec[10] = (unsigned long)arg10; \ - _argvec[11] = (unsigned long)arg11; \ - _argvec[12] = (unsigned long)arg12; \ - __asm__ volatile( \ - VALGRIND_CFI_PROLOGUE \ - "aghi 15,-216\n\t" \ - "lg 2, 8(1)\n\t" \ - "lg 3,16(1)\n\t" \ - "lg 4,24(1)\n\t" \ - "lg 5,32(1)\n\t" \ - "lg 6,40(1)\n\t" \ - "mvc 160(8,15), 48(1)\n\t" \ - "mvc 168(8,15), 56(1)\n\t" \ - "mvc 176(8,15), 64(1)\n\t" \ - "mvc 184(8,15), 72(1)\n\t" \ - "mvc 192(8,15), 80(1)\n\t" \ - "mvc 200(8,15), 88(1)\n\t" \ - "mvc 208(8,15), 96(1)\n\t" \ - "lg 1, 0(1)\n\t" \ - VALGRIND_CALL_NOREDIR_R1 \ - "aghi 15,216\n\t" \ - VALGRIND_CFI_EPILOGUE \ - "lgr %0, 2\n\t" \ - : /*out*/ "=d" (_res) \ - : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \ - : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - - -#endif /* PLAT_s390x_linux */ - -/* ------------------------- mips32-linux ----------------------- */ - -#if defined(PLAT_mips32_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ -"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ -"$25", "$31" - -/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16\n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $4, 4(%1) \n\t" /* arg1*/ \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "subu $29, $29, 16 \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 16 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 24\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 24 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 32\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "nop\n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 32 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 32\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 32 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 40\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 32(%1) \n\t" \ - "sw $4, 28($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 40 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 40\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 32(%1) \n\t" \ - "sw $4, 28($29) \n\t" \ - "lw $4, 36(%1) \n\t" \ - "sw $4, 32($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 40 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 48\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 32(%1) \n\t" \ - "sw $4, 28($29) \n\t" \ - "lw $4, 36(%1) \n\t" \ - "sw $4, 32($29) \n\t" \ - "lw $4, 40(%1) \n\t" \ - "sw $4, 36($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 48 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 48\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 32(%1) \n\t" \ - "sw $4, 28($29) \n\t" \ - "lw $4, 36(%1) \n\t" \ - "sw $4, 32($29) \n\t" \ - "lw $4, 40(%1) \n\t" \ - "sw $4, 36($29) \n\t" \ - "lw $4, 44(%1) \n\t" \ - "sw $4, 40($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 48 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "subu $29, $29, 8 \n\t" \ - "sw $28, 0($29) \n\t" \ - "sw $31, 4($29) \n\t" \ - "lw $4, 20(%1) \n\t" \ - "subu $29, $29, 56\n\t" \ - "sw $4, 16($29) \n\t" \ - "lw $4, 24(%1) \n\t" \ - "sw $4, 20($29) \n\t" \ - "lw $4, 28(%1) \n\t" \ - "sw $4, 24($29) \n\t" \ - "lw $4, 32(%1) \n\t" \ - "sw $4, 28($29) \n\t" \ - "lw $4, 36(%1) \n\t" \ - "sw $4, 32($29) \n\t" \ - "lw $4, 40(%1) \n\t" \ - "sw $4, 36($29) \n\t" \ - "lw $4, 44(%1) \n\t" \ - "sw $4, 40($29) \n\t" \ - "lw $4, 48(%1) \n\t" \ - "sw $4, 44($29) \n\t" \ - "lw $4, 4(%1) \n\t" \ - "lw $5, 8(%1) \n\t" \ - "lw $6, 12(%1) \n\t" \ - "lw $7, 16(%1) \n\t" \ - "lw $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "addu $29, $29, 56 \n\t" \ - "lw $28, 0($29) \n\t" \ - "lw $31, 4($29) \n\t" \ - "addu $29, $29, 8 \n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_mips32_linux */ - -/* ------------------------- nanomips-linux -------------------- */ - -#if defined(PLAT_nanomips_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "$t4", "$t5", "$a0", "$a1", "$a2", \ -"$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", \ -"$t8","$t9", "$at" - -/* These CALL_FN_ macros assume that on mips-linux, sizeof(unsigned - long) == 4. */ - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[1]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[2]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[3]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[4]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[5]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - "lw $a3,16(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[6]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - "lw $a3,16(%1)\n\t" \ - "lw $a4,20(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[7]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - "lw $a3,16(%1)\n\t" \ - "lw $a4,20(%1)\n\t" \ - "lw $a5,24(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[8]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - "lw $a3,16(%1)\n\t" \ - "lw $a4,20(%1)\n\t" \ - "lw $a5,24(%1)\n\t" \ - "lw $a6,28(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[9]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - __asm__ volatile( \ - "lw $t9, 0(%1)\n\t" \ - "lw $a0, 4(%1)\n\t" \ - "lw $a1, 8(%1)\n\t" \ - "lw $a2,12(%1)\n\t" \ - "lw $a3,16(%1)\n\t" \ - "lw $a4,20(%1)\n\t" \ - "lw $a5,24(%1)\n\t" \ - "lw $a6,28(%1)\n\t" \ - "lw $a7,32(%1)\n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[10]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - __asm__ volatile( \ - "addiu $sp, $sp, -16 \n\t" \ - "lw $t9,36(%1) \n\t" \ - "sw $t9, 0($sp) \n\t" \ - "lw $t9, 0(%1) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2,12(%1) \n\t" \ - "lw $a3,16(%1) \n\t" \ - "lw $a4,20(%1) \n\t" \ - "lw $a5,24(%1) \n\t" \ - "lw $a6,28(%1) \n\t" \ - "lw $a7,32(%1) \n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0 \n\t" \ - "addiu $sp, $sp, 16 \n\t" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[11]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - __asm__ volatile( \ - "addiu $sp, $sp, -16 \n\t" \ - "lw $t9,36(%1) \n\t" \ - "sw $t9, 0($sp) \n\t" \ - "lw $t9,40(%1) \n\t" \ - "sw $t9, 4($sp) \n\t" \ - "lw $t9, 0(%1) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2,12(%1) \n\t" \ - "lw $a3,16(%1) \n\t" \ - "lw $a4,20(%1) \n\t" \ - "lw $a5,24(%1) \n\t" \ - "lw $a6,28(%1) \n\t" \ - "lw $a7,32(%1) \n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0 \n\t" \ - "addiu $sp, $sp, 16 \n\t" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[12]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - __asm__ volatile( \ - "addiu $sp, $sp, -16 \n\t" \ - "lw $t9,36(%1) \n\t" \ - "sw $t9, 0($sp) \n\t" \ - "lw $t9,40(%1) \n\t" \ - "sw $t9, 4($sp) \n\t" \ - "lw $t9,44(%1) \n\t" \ - "sw $t9, 8($sp) \n\t" \ - "lw $t9, 0(%1) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2,12(%1) \n\t" \ - "lw $a3,16(%1) \n\t" \ - "lw $a4,20(%1) \n\t" \ - "lw $a5,24(%1) \n\t" \ - "lw $a6,28(%1) \n\t" \ - "lw $a7,32(%1) \n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0 \n\t" \ - "addiu $sp, $sp, 16 \n\t" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long _argvec[13]; \ - volatile unsigned long _res; \ - _argvec[0] = (unsigned long)_orig.nraddr; \ - _argvec[1] = (unsigned long)(arg1); \ - _argvec[2] = (unsigned long)(arg2); \ - _argvec[3] = (unsigned long)(arg3); \ - _argvec[4] = (unsigned long)(arg4); \ - _argvec[5] = (unsigned long)(arg5); \ - _argvec[6] = (unsigned long)(arg6); \ - _argvec[7] = (unsigned long)(arg7); \ - _argvec[8] = (unsigned long)(arg8); \ - _argvec[9] = (unsigned long)(arg9); \ - _argvec[10] = (unsigned long)(arg10); \ - _argvec[11] = (unsigned long)(arg11); \ - _argvec[12] = (unsigned long)(arg12); \ - __asm__ volatile( \ - "addiu $sp, $sp, -16 \n\t" \ - "lw $t9,36(%1) \n\t" \ - "sw $t9, 0($sp) \n\t" \ - "lw $t9,40(%1) \n\t" \ - "sw $t9, 4($sp) \n\t" \ - "lw $t9,44(%1) \n\t" \ - "sw $t9, 8($sp) \n\t" \ - "lw $t9,48(%1) \n\t" \ - "sw $t9,12($sp) \n\t" \ - "lw $t9, 0(%1) \n\t" \ - "lw $a0, 4(%1) \n\t" \ - "lw $a1, 8(%1) \n\t" \ - "lw $a2,12(%1) \n\t" \ - "lw $a3,16(%1) \n\t" \ - "lw $a4,20(%1) \n\t" \ - "lw $a5,24(%1) \n\t" \ - "lw $a6,28(%1) \n\t" \ - "lw $a7,32(%1) \n\t" \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $a0 \n\t" \ - "addiu $sp, $sp, 16 \n\t" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) _res; \ - } while (0) - -#endif /* PLAT_nanomips_linux */ - -/* ------------------------- mips64-linux ------------------------- */ - -#if defined(PLAT_mips64_linux) - -/* These regs are trashed by the hidden call. */ -#define __CALLER_SAVED_REGS "$2", "$3", "$4", "$5", "$6", \ -"$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", \ -"$25", "$31" - -/* These CALL_FN_ macros assume that on mips64-linux, - sizeof(long long) == 8. */ - -#define MIPS64_LONG2REG_CAST(x) ((long long)(long)x) - -#define CALL_FN_W_v(lval, orig) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[1]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - __asm__ volatile( \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "0" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_W(lval, orig, arg1) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[2]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" /* arg1*/ \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[3]; \ - volatile unsigned long long _res; \ - _argvec[0] = _orig.nraddr; \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - - -#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[4]; \ - volatile unsigned long long _res; \ - _argvec[0] = _orig.nraddr; \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[5]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[6]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[7]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[8]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[9]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ - __asm__ volatile( \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $11, 64(%1)\n\t" \ - "ld $25, 0(%1) \n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[10]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ - _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ - __asm__ volatile( \ - "dsubu $29, $29, 8\n\t" \ - "ld $4, 72(%1)\n\t" \ - "sd $4, 0($29)\n\t" \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $11, 64(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "daddu $29, $29, 8\n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ - arg7,arg8,arg9,arg10) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[11]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ - _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ - _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ - __asm__ volatile( \ - "dsubu $29, $29, 16\n\t" \ - "ld $4, 72(%1)\n\t" \ - "sd $4, 0($29)\n\t" \ - "ld $4, 80(%1)\n\t" \ - "sd $4, 8($29)\n\t" \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $11, 64(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "daddu $29, $29, 16\n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[12]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ - _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ - _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ - _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ - __asm__ volatile( \ - "dsubu $29, $29, 24\n\t" \ - "ld $4, 72(%1)\n\t" \ - "sd $4, 0($29)\n\t" \ - "ld $4, 80(%1)\n\t" \ - "sd $4, 8($29)\n\t" \ - "ld $4, 88(%1)\n\t" \ - "sd $4, 16($29)\n\t" \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $11, 64(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "daddu $29, $29, 24\n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ - arg6,arg7,arg8,arg9,arg10, \ - arg11,arg12) \ - do { \ - volatile OrigFn _orig = (orig); \ - volatile unsigned long long _argvec[13]; \ - volatile unsigned long long _res; \ - _argvec[0] = MIPS64_LONG2REG_CAST(_orig.nraddr); \ - _argvec[1] = MIPS64_LONG2REG_CAST(arg1); \ - _argvec[2] = MIPS64_LONG2REG_CAST(arg2); \ - _argvec[3] = MIPS64_LONG2REG_CAST(arg3); \ - _argvec[4] = MIPS64_LONG2REG_CAST(arg4); \ - _argvec[5] = MIPS64_LONG2REG_CAST(arg5); \ - _argvec[6] = MIPS64_LONG2REG_CAST(arg6); \ - _argvec[7] = MIPS64_LONG2REG_CAST(arg7); \ - _argvec[8] = MIPS64_LONG2REG_CAST(arg8); \ - _argvec[9] = MIPS64_LONG2REG_CAST(arg9); \ - _argvec[10] = MIPS64_LONG2REG_CAST(arg10); \ - _argvec[11] = MIPS64_LONG2REG_CAST(arg11); \ - _argvec[12] = MIPS64_LONG2REG_CAST(arg12); \ - __asm__ volatile( \ - "dsubu $29, $29, 32\n\t" \ - "ld $4, 72(%1)\n\t" \ - "sd $4, 0($29)\n\t" \ - "ld $4, 80(%1)\n\t" \ - "sd $4, 8($29)\n\t" \ - "ld $4, 88(%1)\n\t" \ - "sd $4, 16($29)\n\t" \ - "ld $4, 96(%1)\n\t" \ - "sd $4, 24($29)\n\t" \ - "ld $4, 8(%1)\n\t" \ - "ld $5, 16(%1)\n\t" \ - "ld $6, 24(%1)\n\t" \ - "ld $7, 32(%1)\n\t" \ - "ld $8, 40(%1)\n\t" \ - "ld $9, 48(%1)\n\t" \ - "ld $10, 56(%1)\n\t" \ - "ld $11, 64(%1)\n\t" \ - "ld $25, 0(%1)\n\t" /* target->t9 */ \ - VALGRIND_CALL_NOREDIR_T9 \ - "daddu $29, $29, 32\n\t" \ - "move %0, $2\n" \ - : /*out*/ "=r" (_res) \ - : /*in*/ "r" (&_argvec[0]) \ - : /*trash*/ "memory", __CALLER_SAVED_REGS \ - ); \ - lval = (__typeof__(lval)) (long)_res; \ - } while (0) - -#endif /* PLAT_mips64_linux */ - -/* ------------------------------------------------------------------ */ -/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ -/* */ -/* ------------------------------------------------------------------ */ - -/* Some request codes. There are many more of these, but most are not - exposed to end-user view. These are the public ones, all of the - form 0x1000 + small_number. - - Core ones are in the range 0x00000000--0x0000ffff. The non-public - ones start at 0x2000. -*/ - -/* These macros are used by tools -- they must be public, but don't - embed them into other programs. */ -#define VG_USERREQ_TOOL_BASE(a,b) \ - ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16)) -#define VG_IS_TOOL_USERREQ(a, b, v) \ - (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000)) - -/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! - This enum comprises an ABI exported by Valgrind to programs - which use client requests. DO NOT CHANGE THE NUMERIC VALUES OF THESE - ENTRIES, NOR DELETE ANY -- add new ones at the end of the most - relevant group. */ -typedef - enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001, - VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002, - - /* These allow any function to be called from the simulated - CPU but run on the real CPU. Nb: the first arg passed to - the function is always the ThreadId of the running - thread! So CLIENT_CALL0 actually requires a 1 arg - function, etc. */ - VG_USERREQ__CLIENT_CALL0 = 0x1101, - VG_USERREQ__CLIENT_CALL1 = 0x1102, - VG_USERREQ__CLIENT_CALL2 = 0x1103, - VG_USERREQ__CLIENT_CALL3 = 0x1104, - - /* Can be useful in regression testing suites -- eg. can - send Valgrind's output to /dev/null and still count - errors. */ - VG_USERREQ__COUNT_ERRORS = 0x1201, - - /* Allows the client program and/or gdbserver to execute a monitor - command. */ - VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202, - - /* Allows the client program to change a dynamic command line - option. */ - VG_USERREQ__CLO_CHANGE = 0x1203, - - /* These are useful and can be interpreted by any tool that - tracks malloc() et al, by using vg_replace_malloc.c. */ - VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, - VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b, - VG_USERREQ__FREELIKE_BLOCK = 0x1302, - /* Memory pool support. */ - VG_USERREQ__CREATE_MEMPOOL = 0x1303, - VG_USERREQ__DESTROY_MEMPOOL = 0x1304, - VG_USERREQ__MEMPOOL_ALLOC = 0x1305, - VG_USERREQ__MEMPOOL_FREE = 0x1306, - VG_USERREQ__MEMPOOL_TRIM = 0x1307, - VG_USERREQ__MOVE_MEMPOOL = 0x1308, - VG_USERREQ__MEMPOOL_CHANGE = 0x1309, - VG_USERREQ__MEMPOOL_EXISTS = 0x130a, - - /* Allow printfs to valgrind log. */ - /* The first two pass the va_list argument by value, which - assumes it is the same size as or smaller than a UWord, - which generally isn't the case. Hence are deprecated. - The second two pass the vargs by reference and so are - immune to this problem. */ - /* both :: char* fmt, va_list vargs (DEPRECATED) */ - VG_USERREQ__PRINTF = 0x1401, - VG_USERREQ__PRINTF_BACKTRACE = 0x1402, - /* both :: char* fmt, va_list* vargs */ - VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404, - - /* Stack support. */ - VG_USERREQ__STACK_REGISTER = 0x1501, - VG_USERREQ__STACK_DEREGISTER = 0x1502, - VG_USERREQ__STACK_CHANGE = 0x1503, - - /* Wine support */ - VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601, - - /* Querying of debug info. */ - VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701, - - /* Disable/enable error reporting level. Takes a single - Word arg which is the delta to this thread's error - disablement indicator. Hence 1 disables or further - disables errors, and -1 moves back towards enablement. - Other values are not allowed. */ - VG_USERREQ__CHANGE_ERR_DISABLEMENT = 0x1801, - - /* Some requests used for Valgrind internal, such as - self-test or self-hosting. */ - /* Initialise IR injection */ - VG_USERREQ__VEX_INIT_FOR_IRI = 0x1901, - /* Used by Inner Valgrind to inform Outer Valgrind where to - find the list of inner guest threads */ - VG_USERREQ__INNER_THREADS = 0x1902 - } Vg_ClientRequest; - -#if !defined(__GNUC__) -# define __extension__ /* */ -#endif - - -/* Returns the number of Valgrinds this code is running under. That - is, 0 if running natively, 1 if running under Valgrind, 2 if - running under Valgrind which is running under another Valgrind, - etc. */ -#define RUNNING_ON_VALGRIND \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \ - VG_USERREQ__RUNNING_ON_VALGRIND, \ - 0, 0, 0, 0, 0) \ - - -/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + - _qzz_len - 1]. Useful if you are debugging a JITter or some such, - since it provides a way to make sure valgrind will retranslate the - invalidated area. Returns no value. */ -#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DISCARD_TRANSLATIONS, \ - _qzz_addr, _qzz_len, 0, 0, 0) - -#define VALGRIND_INNER_THREADS(_qzz_addr) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__INNER_THREADS, \ - _qzz_addr, 0, 0, 0, 0) - - -/* These requests are for getting Valgrind itself to print something. - Possibly with a backtrace. This is a really ugly hack. The return value - is the number of characters printed, excluding the "**** " part at the - start and the backtrace (if present). */ - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -/* Modern GCC will optimize the static routine out if unused, - and unused attribute will shut down warnings about it. */ -static int VALGRIND_PRINTF(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF(const char *format, ...) -{ -#if defined(NVALGRIND) - (void)format; - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) || defined(__MINGW64__) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) || defined(__MINGW64__) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - -#if defined(__GNUC__) || defined(__INTEL_COMPILER) && !defined(_MSC_VER) -static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) - __attribute__((format(__printf__, 1, 2), __unused__)); -#endif -static int -#if defined(_MSC_VER) -__inline -#endif -VALGRIND_PRINTF_BACKTRACE(const char *format, ...) -{ -#if defined(NVALGRIND) - (void)format; - return 0; -#else /* NVALGRIND */ -#if defined(_MSC_VER) || defined(__MINGW64__) - uintptr_t _qzz_res; -#else - unsigned long _qzz_res; -#endif - va_list vargs; - va_start(vargs, format); -#if defined(_MSC_VER) || defined(__MINGW64__) - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (uintptr_t)format, - (uintptr_t)&vargs, - 0, 0, 0); -#else - _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0, - VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF, - (unsigned long)format, - (unsigned long)&vargs, - 0, 0, 0); -#endif - va_end(vargs); - return (int)_qzz_res; -#endif /* NVALGRIND */ -} - - -/* These requests allow control to move from the simulated CPU to the - real CPU, calling an arbitrary function. - - Note that the current ThreadId is inserted as the first argument. - So this call: - - VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) - - requires f to have this signature: - - Word f(Word tid, Word arg1, Word arg2) - - where "Word" is a word-sized type. - - Note that these client requests are not entirely reliable. For example, - if you call a function with them that subsequently calls printf(), - there's a high chance Valgrind will crash. Generally, your prospects of - these working are made higher if the called function does not refer to - any global variables, and does not refer to any libc or other functions - (printf et al). Any kind of entanglement with libc or dynamic linking is - likely to have a bad outcome, for tricky reasons which we've grappled - with a lot in the past. -*/ -#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL0, \ - _qyy_fn, \ - 0, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL1, \ - _qyy_fn, \ - _qyy_arg1, 0, 0, 0) - -#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL2, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, 0, 0) - -#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \ - VG_USERREQ__CLIENT_CALL3, \ - _qyy_fn, \ - _qyy_arg1, _qyy_arg2, \ - _qyy_arg3, 0) - - -/* Counts the number of errors that have been recorded by a tool. Nb: - the tool must record the errors with VG_(maybe_record_error)() or - VG_(unique_error)() for them to be counted. */ -#define VALGRIND_COUNT_ERRORS \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \ - 0 /* default return */, \ - VG_USERREQ__COUNT_ERRORS, \ - 0, 0, 0, 0, 0) - -/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing - when heap blocks are allocated in order to give accurate results. This - happens automatically for the standard allocator functions such as - malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete, - delete[], etc. - - But if your program uses a custom allocator, this doesn't automatically - happen, and Valgrind will not do as well. For example, if you allocate - superblocks with mmap() and then allocates chunks of the superblocks, all - Valgrind's observations will be at the mmap() level and it won't know that - the chunks should be considered separate entities. In Memcheck's case, - that means you probably won't get heap block overrun detection (because - there won't be redzones marked as unaddressable) and you definitely won't - get any leak detection. - - The following client requests allow a custom allocator to be annotated so - that it can be handled accurately by Valgrind. - - VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated - by a malloc()-like function. For Memcheck (an illustrative case), this - does two things: - - - It records that the block has been allocated. This means any addresses - within the block mentioned in error messages will be - identified as belonging to the block. It also means that if the block - isn't freed it will be detected by the leak checker. - - - It marks the block as being addressable and undefined (if 'is_zeroed' is - not set), or addressable and defined (if 'is_zeroed' is set). This - controls how accesses to the block by the program are handled. - - 'addr' is the start of the usable block (ie. after any - redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator - can apply redzones -- these are blocks of padding at the start and end of - each block. Adding redzones is recommended as it makes it much more likely - Valgrind will spot block overruns. `is_zeroed' indicates if the memory is - zeroed (or filled with another predictable value), as is the case for - calloc(). - - VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a - heap block -- that will be used by the client program -- is allocated. - It's best to put it at the outermost level of the allocator if possible; - for example, if you have a function my_alloc() which calls - internal_alloc(), and the client request is put inside internal_alloc(), - stack traces relating to the heap block will contain entries for both - my_alloc() and internal_alloc(), which is probably not what you want. - - For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out - custom blocks from within a heap block, B, that has been allocated with - malloc/calloc/new/etc, then block B will be *ignored* during leak-checking - -- the custom blocks will take precedence. - - VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For - Memcheck, it does two things: - - - It records that the block has been deallocated. This assumes that the - block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - It marks the block as being unaddressable. - - VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a - heap block is deallocated. - - VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For - Memcheck, it does four things: - - - It records that the size of a block has been changed. This assumes that - the block was annotated as having been allocated via - VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued. - - - If the block shrunk, it marks the freed memory as being unaddressable. - - - If the block grew, it marks the new area as undefined and defines a red - zone past the end of the new block. - - - The V-bits of the overlap between the old and the new block are preserved. - - VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new block - and before deallocation of the old block. - - In many cases, these three client requests will not be enough to get your - allocator working well with Memcheck. More specifically, if your allocator - writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call - will be necessary to mark the memory as addressable just before the zeroing - occurs, otherwise you'll get a lot of invalid write errors. For example, - you'll need to do this if your allocator recycles freed blocks, but it - zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK). - Alternatively, if your allocator reuses freed blocks for allocator-internal - data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary. - - Really, what's happening is a blurring of the lines between the client - program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the - memory should be considered unaddressable to the client program, but the - allocator knows more than the rest of the client program and so may be able - to safely access it. Extra client requests are necessary for Valgrind to - understand the distinction between the allocator and the rest of the - program. - - Ignored if addr == 0. -*/ -#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MALLOCLIKE_BLOCK, \ - addr, sizeB, rzB, is_zeroed, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RESIZEINPLACE_BLOCK, \ - addr, oldSizeB, newSizeB, rzB, 0) - -/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details. - Ignored if addr == 0. -*/ -#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__FREELIKE_BLOCK, \ - addr, rzB, 0, 0, 0) - -/* Create a memory pool. */ -#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ - pool, rzB, is_zeroed, 0, 0) - -/* Create a memory pool with some flags specifying extended behaviour. - When flags is zero, the behaviour is identical to VALGRIND_CREATE_MEMPOOL. - - The flag VALGRIND_MEMPOOL_METAPOOL specifies that the pieces of memory - associated with the pool using VALGRIND_MEMPOOL_ALLOC will be used - by the application as superblocks to dole out MALLOC_LIKE blocks using - VALGRIND_MALLOCLIKE_BLOCK. In other words, a meta pool is a "2 levels" - pool : first level is the blocks described by VALGRIND_MEMPOOL_ALLOC. - The second level blocks are described using VALGRIND_MALLOCLIKE_BLOCK. - Note that the association between the pool and the second level blocks - is implicit : second level blocks will be located inside first level - blocks. It is necessary to use the VALGRIND_MEMPOOL_METAPOOL flag - for such 2 levels pools, as otherwise valgrind will detect overlapping - memory blocks, and will abort execution (e.g. during leak search). - - Such a meta pool can also be marked as an 'auto free' pool using the flag - VALGRIND_MEMPOOL_AUTO_FREE, which must be OR-ed together with the - VALGRIND_MEMPOOL_METAPOOL. For an 'auto free' pool, VALGRIND_MEMPOOL_FREE - will automatically free the second level blocks that are contained - inside the first level block freed with VALGRIND_MEMPOOL_FREE. - In other words, calling VALGRIND_MEMPOOL_FREE will cause implicit calls - to VALGRIND_FREELIKE_BLOCK for all the second level blocks included - in the first level block. - Note: it is an error to use the VALGRIND_MEMPOOL_AUTO_FREE flag - without the VALGRIND_MEMPOOL_METAPOOL flag. -*/ -#define VALGRIND_MEMPOOL_AUTO_FREE 1 -#define VALGRIND_MEMPOOL_METAPOOL 2 -#define VALGRIND_CREATE_MEMPOOL_EXT(pool, rzB, is_zeroed, flags) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CREATE_MEMPOOL, \ - pool, rzB, is_zeroed, flags, 0) - -/* Destroy a memory pool. */ -#define VALGRIND_DESTROY_MEMPOOL(pool) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DESTROY_MEMPOOL, \ - pool, 0, 0, 0, 0) - -/* Associate a piece of memory with a memory pool. */ -#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_ALLOC, \ - pool, addr, size, 0, 0) - -/* Disassociate a piece of memory from a memory pool. */ -#define VALGRIND_MEMPOOL_FREE(pool, addr) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_FREE, \ - pool, addr, 0, 0, 0) - -/* Disassociate any pieces outside a particular range. */ -#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_TRIM, \ - pool, addr, size, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MOVE_MEMPOOL, \ - poolA, poolB, 0, 0, 0) - -/* Resize and/or move a piece associated with a memory pool. */ -#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__MEMPOOL_CHANGE, \ - pool, addrA, addrB, size, 0) - -/* Return 1 if a mempool exists, else 0. */ -#define VALGRIND_MEMPOOL_EXISTS(pool) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MEMPOOL_EXISTS, \ - pool, 0, 0, 0, 0) - -/* Mark a piece of memory as being a stack. Returns a stack id. - start is the lowest addressable stack byte, end is the highest - addressable stack byte. */ -#define VALGRIND_STACK_REGISTER(start, end) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__STACK_REGISTER, \ - start, end, 0, 0, 0) - -/* Unmark the piece of memory associated with a stack id as being a - stack. */ -#define VALGRIND_STACK_DEREGISTER(id) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_DEREGISTER, \ - id, 0, 0, 0, 0) - -/* Change the start and end address of the stack id. - start is the new lowest addressable stack byte, end is the new highest - addressable stack byte. */ -#define VALGRIND_STACK_CHANGE(id, start, end) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__STACK_CHANGE, \ - id, start, end, 0, 0) - -/* Load PDB debug info for Wine PE image_map. */ -#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__LOAD_PDB_DEBUGINFO, \ - fd, ptr, total_size, delta, 0) - -/* Map a code address to a source file name and line number. buf64 - must point to a 64-byte buffer in the caller's address space. The - result will be dumped in there and is guaranteed to be zero - terminated. If no info is found, the first byte is set to zero. */ -#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \ - (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \ - VG_USERREQ__MAP_IP_TO_SRCLOC, \ - addr, buf64, 0, 0, 0) - -/* Disable error reporting for this thread. Behaves in a stack like - way, so you can safely call this multiple times provided that - VALGRIND_ENABLE_ERROR_REPORTING is called the same number of times - to re-enable reporting. The first call of this macro disables - reporting. Subsequent calls have no effect except to increase the - number of VALGRIND_ENABLE_ERROR_REPORTING calls needed to re-enable - reporting. Child threads do not inherit this setting from their - parents -- they are always created with reporting enabled. */ -#define VALGRIND_DISABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - 1, 0, 0, 0, 0) - -/* Re-enable error reporting, as per comments on - VALGRIND_DISABLE_ERROR_REPORTING. */ -#define VALGRIND_ENABLE_ERROR_REPORTING \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \ - -1, 0, 0, 0, 0) - -/* Execute a monitor command from the client program. - If a connection is opened with GDB, the output will be sent - according to the output mode set for vgdb. - If no connection is opened, output will go to the log output. - Returns 1 if command not recognised, 0 otherwise. */ -#define VALGRIND_MONITOR_COMMAND(command) \ - VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \ - command, 0, 0, 0, 0) - - -/* Change the value of a dynamic command line option. - Note that unknown or not dynamically changeable options - will cause a warning message to be output. */ -#define VALGRIND_CLO_CHANGE(option) \ - VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CLO_CHANGE, \ - option, 0, 0, 0, 0) - - -#undef PLAT_x86_darwin -#undef PLAT_amd64_darwin -#undef PLAT_x86_win32 -#undef PLAT_amd64_win64 -#undef PLAT_x86_linux -#undef PLAT_amd64_linux -#undef PLAT_ppc32_linux -#undef PLAT_ppc64be_linux -#undef PLAT_ppc64le_linux -#undef PLAT_arm_linux -#undef PLAT_s390x_linux -#undef PLAT_mips32_linux -#undef PLAT_mips64_linux -#undef PLAT_nanomips_linux -#undef PLAT_x86_solaris -#undef PLAT_amd64_solaris - -#endif /* __VALGRIND_H */ diff --git a/testing/capi/instrument-hooks/includes/zig.h b/testing/capi/instrument-hooks/includes/zig.h deleted file mode 100644 index 2d9e7a56..00000000 --- a/testing/capi/instrument-hooks/includes/zig.h +++ /dev/null @@ -1,4209 +0,0 @@ -#undef linux - -#include -#include - -#if defined(_MSC_VER) -#define zig_msvc -#elif defined(__clang__) -#define zig_clang -#define zig_gnuc -#elif defined(__GNUC__) -#define zig_gcc -#define zig_gnuc -#elif defined(__IBMC__) -#define zig_xlc -#elif defined(__TINYC__) -#define zig_tinyc -#elif defined(__slimcc__) -#define zig_slimcc -#endif - -#if defined(__aarch64__) || (defined(zig_msvc) && defined(_M_ARM64)) -#define zig_aarch64 -#elif defined(__thumb__) || (defined(zig_msvc) && defined(_M_ARM)) -#define zig_thumb -#define zig_arm -#elif defined(__arm__) -#define zig_arm -#elif defined(__hexagon__) -#define zig_hexagon -#elif defined(__loongarch32) -#define zig_loongarch32 -#define zig_loongarch -#elif defined(__loongarch64) -#define zig_loongarch64 -#define zig_loongarch -#elif defined(__mips64) -#define zig_mips64 -#define zig_mips -#elif defined(__mips__) -#define zig_mips32 -#define zig_mips -#elif defined(__powerpc64__) -#define zig_powerpc64 -#define zig_powerpc -#elif defined(__powerpc__) -#define zig_powerpc32 -#define zig_powerpc -#elif defined(__riscv) && __riscv_xlen == 32 -#define zig_riscv32 -#define zig_riscv -#elif defined(__riscv) && __riscv_xlen == 64 -#define zig_riscv64 -#define zig_riscv -#elif defined(__s390x__) -#define zig_s390x -#elif defined(__sparc__) && defined(__arch64__) -#define zig_sparc64 -#define zig_sparc -#elif defined(__sparc__) -#define zig_sparc32 -#define zig_sparc -#elif defined(__wasm32__) -#define zig_wasm32 -#define zig_wasm -#elif defined(__wasm64__) -#define zig_wasm64 -#define zig_wasm -#elif defined(__i386__) || (defined(zig_msvc) && defined(_M_IX86)) -#define zig_x86_32 -#define zig_x86 -#elif defined (__x86_64__) || (defined(zig_msvc) && defined(_M_X64)) -#define zig_x86_64 -#define zig_x86 -#endif - -#if defined(zig_msvc) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define zig_little_endian 1 -#define zig_big_endian 0 -#else -#define zig_little_endian 0 -#define zig_big_endian 1 -#endif - -#if defined(_AIX) -#define zig_aix -#elif defined(__MACH__) -#define zig_darwin -#elif defined(__DragonFly__) -#define zig_dragonfly -#define zig_bsd -#elif defined(__EMSCRIPTEN__) -#define zig_emscripten -#elif defined(__FreeBSD__) -#define zig_freebsd -#define zig_bsd -#elif defined(__Fuchsia__) -#define zig_fuchsia -#elif defined(__HAIKU__) -#define zig_haiku -#elif defined(__gnu_hurd__) -#define zig_hurd -#elif defined(__linux__) -#define zig_linux -#elif defined(__NetBSD__) -#define zig_netbsd -#define zig_bsd -#elif defined(__OpenBSD__) -#define zig_openbsd -#define zig_bsd -#elif defined(__SVR4) -#define zig_solaris -#elif defined(__wasi__) -#define zig_wasi -#elif defined(_WIN32) -#define zig_windows -#elif defined(__MVS__) -#define zig_zos -#endif - -#if defined(zig_windows) -#define zig_coff -#elif defined(__ELF__) -#define zig_elf -#elif defined(zig_zos) -#define zig_goff -#elif defined(zig_darwin) -#define zig_macho -#elif defined(zig_aix) -#define zig_xcoff -#endif - -#define zig_concat(lhs, rhs) lhs##rhs -#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs) - -#if defined(__has_include) -#define zig_has_include(include) __has_include(include) -#else -#define zig_has_include(include) 0 -#endif - -#if defined(__has_builtin) -#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) -#else -#define zig_has_builtin(builtin) 0 -#endif -#define zig_expand_has_builtin(b) zig_has_builtin(b) - -#if defined(__has_attribute) -#define zig_has_attribute(attribute) __has_attribute(attribute) -#else -#define zig_has_attribute(attribute) 0 -#endif - -#if __STDC_VERSION__ >= 202311L -#define zig_threadlocal thread_local -#elif __STDC_VERSION__ >= 201112L -#define zig_threadlocal _Thread_local -#elif defined(zig_gnuc) || defined(zig_slimcc) -#define zig_threadlocal __thread -#elif defined(zig_msvc) -#define zig_threadlocal __declspec(thread) -#else -#define zig_threadlocal zig_threadlocal_unavailable -#endif - -#if defined(zig_msvc) -#define zig_const_arr -#define zig_callconv(c) __##c -#else -#define zig_const_arr static const -#define zig_callconv(c) __attribute__((c)) -#endif - -#if zig_has_attribute(naked) || defined(zig_gcc) -#define zig_naked_decl __attribute__((naked)) -#define zig_naked __attribute__((naked)) -#elif defined(zig_msvc) -#define zig_naked_decl -#define zig_naked __declspec(naked) -#else -#define zig_naked_decl zig_naked_unavailable -#define zig_naked zig_naked_unavailable -#endif - -#if zig_has_attribute(cold) -#define zig_cold __attribute__((cold)) -#else -#define zig_cold -#endif - -#if zig_has_attribute(flatten) -#define zig_maybe_flatten __attribute__((flatten)) -#else -#define zig_maybe_flatten -#endif - -#if zig_has_attribute(noinline) -#define zig_never_inline __attribute__((noinline)) zig_maybe_flatten -#elif defined(zig_msvc) -#define zig_never_inline __declspec(noinline) zig_maybe_flatten -#else -#define zig_never_inline zig_never_inline_unavailable -#endif - -#if zig_has_attribute(not_tail_called) -#define zig_never_tail __attribute__((not_tail_called)) zig_never_inline -#else -#define zig_never_tail zig_never_tail_unavailable -#endif - -#if zig_has_attribute(musttail) -#define zig_always_tail __attribute__((musttail)) -#else -#define zig_always_tail zig_always_tail_unavailable -#endif - -#if __STDC_VERSION__ >= 199901L -#define zig_restrict restrict -#elif defined(zig_gnuc) || defined(zig_tinyc) -#define zig_restrict __restrict -#else -#define zig_restrict -#endif - -#if zig_has_attribute(no_builtin) -#define zig_no_builtin __attribute__((no_builtin)) -#else -#define zig_no_builtin -#endif - -#if zig_has_attribute(aligned) || defined(zig_tinyc) -#define zig_under_align(alignment) __attribute__((aligned(alignment))) -#elif defined(zig_msvc) -#define zig_under_align(alignment) __declspec(align(alignment)) -#else -#define zig_under_align zig_align_unavailable -#endif - -#if __STDC_VERSION__ >= 202311L -#define zig_align(alignment) alignas(alignment) -#elif __STDC_VERSION__ >= 201112L -#define zig_align(alignment) _Alignas(alignment) -#else -#define zig_align(alignment) zig_under_align(alignment) -#endif - -#if zig_has_attribute(aligned) || defined(zig_tinyc) -#define zig_align_fn(alignment) __attribute__((aligned(alignment))) -#elif defined(zig_msvc) -#define zig_align_fn(alignment) -#else -#define zig_align_fn zig_align_fn_unavailable -#endif - -#if zig_has_attribute(packed) || defined(zig_tinyc) -#define zig_packed(definition) __attribute__((packed)) definition -#elif defined(zig_msvc) -#define zig_packed(definition) __pragma(pack(1)) definition __pragma(pack()) -#else -#define zig_packed(definition) zig_packed_unavailable -#endif - -#if zig_has_attribute(section) || defined(zig_tinyc) -#define zig_linksection(name) __attribute__((section(name))) -#define zig_linksection_fn zig_linksection -#elif defined(zig_msvc) -#define zig_linksection(name) __pragma(section(name, read, write)) __declspec(allocate(name)) -#define zig_linksection_fn(name) __pragma(section(name, read, execute)) __declspec(code_seg(name)) -#else -#define zig_linksection(name) zig_linksection_unavailable -#define zig_linksection_fn zig_linksection -#endif - -#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_unreachable() __builtin_unreachable() -#elif defined(zig_msvc) -#define zig_unreachable() __assume(0) -#else -#define zig_unreachable() -#endif - -#if defined(__cplusplus) -#define zig_extern extern "C" -#else -#define zig_extern extern -#endif - -#if defined(zig_msvc) -#if defined(zig_x86_64) -#define zig_mangle_c(symbol) symbol -#else /* zig_x86_64 */ -#define zig_mangle_c(symbol) "_" symbol -#endif /* zig_x86_64 */ -#else /* zig_msvc */ -#if defined(zig_macho) -#define zig_mangle_c(symbol) "_" symbol -#else /* zig_macho */ -#define zig_mangle_c(symbol) symbol -#endif /* zig_macho */ -#endif /* zig_msvc */ - -#if defined(zig_msvc) -#define zig_export(symbol, name) ; \ - __pragma(comment(linker, "/alternatename:" zig_mangle_c(name) "=" zig_mangle_c(symbol))) -#elif (zig_has_attribute(alias) || defined(zig_tinyc)) && !defined(zig_macho) -#define zig_export(symbol, name) __attribute__((alias(symbol))) -#else -#define zig_export(symbol, name) ; \ - __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) -#endif - -#define zig_mangled_tentative zig_mangled -#define zig_mangled_final zig_mangled -#if defined(zig_msvc) -#define zig_mangled(mangled, unmangled) ; \ - zig_export(#mangled, unmangled) -#define zig_mangled_export(mangled, unmangled, symbol) \ - zig_export(unmangled, #mangled) \ - zig_export(symbol, unmangled) -#else /* zig_msvc */ -#define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled)) -#define zig_mangled_export(mangled, unmangled, symbol) \ - zig_mangled_final(mangled, unmangled) \ - zig_export(symbol, unmangled) -#endif /* zig_msvc */ - -#if defined(zig_msvc) -#define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args;\ - __pragma(comment(linker, "/alternatename:" zig_mangle_c(#fn_name) "=" zig_mangle_c(#libc_name))); -#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, libc_name, sig_args, call_args) -#else /* zig_msvc */ -#define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args __asm(zig_mangle_c(#libc_name)); -#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type libc_name sig_args; \ - static inline Type fn_name sig_args { return libc_name call_args; } -#endif - -#define zig_expand_import_0(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, libc_name, sig_args, call_args) -#define zig_expand_import_1(Type, fn_name, libc_name, sig_args, call_args) zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) - -#if zig_has_attribute(weak) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_weak_linkage __attribute__((weak)) -#define zig_weak_linkage_fn __attribute__((weak)) -#elif defined(zig_msvc) -#define zig_weak_linkage __declspec(selectany) -#define zig_weak_linkage_fn -#else -#define zig_weak_linkage zig_weak_linkage_unavailable -#define zig_weak_linkage_fn zig_weak_linkage_unavailable -#endif - -#if defined(zig_gnuc) || defined(zig_tinyc) || defined(zig_slimcc) -#define zig_gnuc_asm -#endif - -#if zig_has_builtin(trap) -#define zig_trap() __builtin_trap() -#elif defined(zig_msvc) - -#if defined(zig_x86) -#define zig_trap() __ud2() -#else -#define zig_trap() __fastfail(7) -#endif - -#elif defined(zig_gnuc_asm) - -#if defined(zig_thumb) -#define zig_trap() __asm__ volatile("udf #0xfe") -#elif defined(zig_arm) || defined(zig_aarch64) -#define zig_trap() __asm__ volatile("udf #0xfdee") -#elif defined(zig_hexagon) -#define zig_trap() __asm__ volatile("r27:26 = memd(#0xbadc0fee)") -#elif defined(zig_loongarch) || defined(zig_powerpc) -#define zig_trap() __asm__ volatile(".word 0x0") -#elif defined(zig_mips) -#define zig_trap() __asm__ volatile(".word 0x3d") -#elif defined(zig_riscv) -#define zig_trap() __asm__ volatile("unimp") -#elif defined(zig_s390x) -#define zig_trap() __asm__ volatile("j 0x2") -#elif defined(zig_sparc) -#define zig_trap() __asm__ volatile("illtrap") -#elif defined(zig_x86) -#define zig_trap() __asm__ volatile("ud2") -#else -#define zig_trap() zig_trap_unavailable -#endif - -#else -#define zig_trap() zig_trap_unavailable -#endif - -#if zig_has_builtin(debugtrap) -#define zig_breakpoint() __builtin_debugtrap() -#elif defined(zig_msvc) -#define zig_breakpoint() __debugbreak() -#elif defined(zig_gnuc_asm) - -#if defined(zig_arm) -#define zig_breakpoint() __asm__ volatile("bkpt #0x0") -#elif defined(zig_aarch64) -#define zig_breakpoint() __asm__ volatile("brk #0xf000") -#elif defined(zig_hexagon) -#define zig_breakpoint() __asm__ volatile("brkpt") -#elif defined(zig_loongarch) -#define zig_breakpoint() __asm__ volatile("break 0x0") -#elif defined(zig_mips) -#define zig_breakpoint() __asm__ volatile("break") -#elif defined(zig_powerpc) -#define zig_breakpoint() __asm__ volatile("trap") -#elif defined(zig_riscv) -#define zig_breakpoint() __asm__ volatile("ebreak") -#elif defined(zig_s390x) -#define zig_breakpoint() __asm__ volatile("j 0x6") -#elif defined(zig_sparc) -#define zig_breakpoint() __asm__ volatile("ta 0x1") -#elif defined(zig_x86) -#define zig_breakpoint() __asm__ volatile("int $0x3") -#else -#define zig_breakpoint() zig_breakpoint_unavailable -#endif - -#else -#define zig_breakpoint() zig_breakpoint_unavailable -#endif - -#if zig_has_builtin(return_address) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_return_address() __builtin_extract_return_addr(__builtin_return_address(0)) -#elif defined(zig_msvc) -#define zig_return_address() _ReturnAddress() -#else -#define zig_return_address() 0 -#endif - -#if zig_has_builtin(frame_address) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_frame_address() __builtin_frame_address(0) -#elif defined(zig_msvc) -#define zig_frame_address() _AddressOfReturnAddress() -#else -#define zig_frame_address() 0 -#endif - -#if zig_has_builtin(prefetch) || defined(zig_gcc) -#define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality) -#else -#define zig_prefetch(addr, rw, locality) -#endif - -#if zig_has_builtin(memory_size) && zig_has_builtin(memory_grow) -#define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) -#define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) -#else -#define zig_wasm_memory_size(index) zig_unimplemented() -#define zig_wasm_memory_grow(index, delta) zig_unimplemented() -#endif - -#if __STDC_VERSION__ >= 202311L -#define zig_noreturn [[noreturn]] -#elif __STDC_VERSION__ >= 201112L -#define zig_noreturn _Noreturn -#elif zig_has_attribute(noreturn) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_noreturn __attribute__((noreturn)) -#elif defined(zig_msvc) -#define zig_noreturn __declspec(noreturn) -#else -#define zig_noreturn -#endif - -#define zig_compiler_rt_abbrev_uint32_t si -#define zig_compiler_rt_abbrev_int32_t si -#define zig_compiler_rt_abbrev_uint64_t di -#define zig_compiler_rt_abbrev_int64_t di -#define zig_compiler_rt_abbrev_zig_u128 ti -#define zig_compiler_rt_abbrev_zig_i128 ti -#define zig_compiler_rt_abbrev_zig_f16 hf -#define zig_compiler_rt_abbrev_zig_f32 sf -#define zig_compiler_rt_abbrev_zig_f64 df -#define zig_compiler_rt_abbrev_zig_f80 xf -#define zig_compiler_rt_abbrev_zig_f128 tf - -zig_extern void *memcpy (void *zig_restrict, void const *zig_restrict, size_t); -zig_extern void *memset (void *, int, size_t); - -/* ================ Bool and 8/16/32/64-bit Integer Support ================= */ - -#include - -#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T)) - -#if __STDC_VERSION__ >= 202311L -/* bool, true, and false are provided by the language. */ -#elif __STDC_VERSION__ >= 199901L || zig_has_include() -#include -#else -typedef char bool; -#define false 0 -#define true 1 -#endif - -#if __STDC_VERSION__ >= 199901L || defined(zig_msvc) || zig_has_include() -#include -#else -#if SCHAR_MIN == ~0x7F && SCHAR_MAX == 0x7F && UCHAR_MAX == 0xFF -typedef unsigned char uint8_t; -typedef signed char int8_t; -#define INT8_C(c) c -#define UINT8_C(c) c##U -#elif SHRT_MIN == ~0x7F && SHRT_MAX == 0x7F && USHRT_MAX == 0xFF -typedef unsigned short uint8_t; -typedef signed short int8_t; -#define INT8_C(c) c -#define UINT8_C(c) c##U -#elif INT_MIN == ~0x7F && INT_MAX == 0x7F && UINT_MAX == 0xFF -typedef unsigned int uint8_t; -typedef signed int int8_t; -#define INT8_C(c) c -#define UINT8_C(c) c##U -#elif LONG_MIN == ~0x7F && LONG_MAX == 0x7F && ULONG_MAX == 0xFF -typedef unsigned long uint8_t; -typedef signed long int8_t; -#define INT8_C(c) c##L -#define UINT8_C(c) c##LU -#elif LLONG_MIN == ~0x7F && LLONG_MAX == 0x7F && ULLONG_MAX == 0xFF -typedef unsigned long long uint8_t; -typedef signed long long int8_t; -#define INT8_C(c) c##LL -#define UINT8_C(c) c##LLU -#endif -#define INT8_MIN (~INT8_C(0x7F)) -#define INT8_MAX ( INT8_C(0x7F)) -#define UINT8_MAX ( INT8_C(0xFF)) - -#if SCHAR_MIN == ~0x7FFF && SCHAR_MAX == 0x7FFF && UCHAR_MAX == 0xFFFF -typedef unsigned char uint16_t; -typedef signed char int16_t; -#define INT16_C(c) c -#define UINT16_C(c) c##U -#elif SHRT_MIN == ~0x7FFF && SHRT_MAX == 0x7FFF && USHRT_MAX == 0xFFFF -typedef unsigned short uint16_t; -typedef signed short int16_t; -#define INT16_C(c) c -#define UINT16_C(c) c##U -#elif INT_MIN == ~0x7FFF && INT_MAX == 0x7FFF && UINT_MAX == 0xFFFF -typedef unsigned int uint16_t; -typedef signed int int16_t; -#define INT16_C(c) c -#define UINT16_C(c) c##U -#elif LONG_MIN == ~0x7FFF && LONG_MAX == 0x7FFF && ULONG_MAX == 0xFFFF -typedef unsigned long uint16_t; -typedef signed long int16_t; -#define INT16_C(c) c##L -#define UINT16_C(c) c##LU -#elif LLONG_MIN == ~0x7FFF && LLONG_MAX == 0x7FFF && ULLONG_MAX == 0xFFFF -typedef unsigned long long uint16_t; -typedef signed long long int16_t; -#define INT16_C(c) c##LL -#define UINT16_C(c) c##LLU -#endif -#define INT16_MIN (~INT16_C(0x7FFF)) -#define INT16_MAX ( INT16_C(0x7FFF)) -#define UINT16_MAX ( INT16_C(0xFFFF)) - -#if SCHAR_MIN == ~0x7FFFFFFF && SCHAR_MAX == 0x7FFFFFFF && UCHAR_MAX == 0xFFFFFFFF -typedef unsigned char uint32_t; -typedef signed char int32_t; -#define INT32_C(c) c -#define UINT32_C(c) c##U -#elif SHRT_MIN == ~0x7FFFFFFF && SHRT_MAX == 0x7FFFFFFF && USHRT_MAX == 0xFFFFFFFF -typedef unsigned short uint32_t; -typedef signed short int32_t; -#define INT32_C(c) c -#define UINT32_C(c) c##U -#elif INT_MIN == ~0x7FFFFFFF && INT_MAX == 0x7FFFFFFF && UINT_MAX == 0xFFFFFFFF -typedef unsigned int uint32_t; -typedef signed int int32_t; -#define INT32_C(c) c -#define UINT32_C(c) c##U -#elif LONG_MIN == ~0x7FFFFFFF && LONG_MAX == 0x7FFFFFFF && ULONG_MAX == 0xFFFFFFFF -typedef unsigned long uint32_t; -typedef signed long int32_t; -#define INT32_C(c) c##L -#define UINT32_C(c) c##LU -#elif LLONG_MIN == ~0x7FFFFFFF && LLONG_MAX == 0x7FFFFFFF && ULLONG_MAX == 0xFFFFFFFF -typedef unsigned long long uint32_t; -typedef signed long long int32_t; -#define INT32_C(c) c##LL -#define UINT32_C(c) c##LLU -#endif -#define INT32_MIN (~INT32_C(0x7FFFFFFF)) -#define INT32_MAX ( INT32_C(0x7FFFFFFF)) -#define UINT32_MAX ( INT32_C(0xFFFFFFFF)) - -#if SCHAR_MIN == ~0x7FFFFFFFFFFFFFFF && SCHAR_MAX == 0x7FFFFFFFFFFFFFFF && UCHAR_MAX == 0xFFFFFFFFFFFFFFFF -typedef unsigned char uint64_t; -typedef signed char int64_t; -#define INT64_C(c) c -#define UINT64_C(c) c##U -#elif SHRT_MIN == ~0x7FFFFFFFFFFFFFFF && SHRT_MAX == 0x7FFFFFFFFFFFFFFF && USHRT_MAX == 0xFFFFFFFFFFFFFFFF -typedef unsigned short uint64_t; -typedef signed short int64_t; -#define INT64_C(c) c -#define UINT64_C(c) c##U -#elif INT_MIN == ~0x7FFFFFFFFFFFFFFF && INT_MAX == 0x7FFFFFFFFFFFFFFF && UINT_MAX == 0xFFFFFFFFFFFFFFFF -typedef unsigned int uint64_t; -typedef signed int int64_t; -#define INT64_C(c) c -#define UINT64_C(c) c##U -#elif LONG_MIN == ~0x7FFFFFFFFFFFFFFF && LONG_MAX == 0x7FFFFFFFFFFFFFFF && ULONG_MAX == 0xFFFFFFFFFFFFFFFF -typedef unsigned long uint64_t; -typedef signed long int64_t; -#define INT64_C(c) c##L -#define UINT64_C(c) c##LU -#elif LLONG_MIN == ~0x7FFFFFFFFFFFFFFF && LLONG_MAX == 0x7FFFFFFFFFFFFFFF && ULLONG_MAX == 0xFFFFFFFFFFFFFFFF -typedef unsigned long long uint64_t; -typedef signed long long int64_t; -#define INT64_C(c) c##LL -#define UINT64_C(c) c##LLU -#endif -#define INT64_MIN (~INT64_C(0x7FFFFFFFFFFFFFFF)) -#define INT64_MAX ( INT64_C(0x7FFFFFFFFFFFFFFF)) -#define UINT64_MAX ( INT64_C(0xFFFFFFFFFFFFFFFF)) - -typedef size_t uintptr_t; -typedef ptrdiff_t intptr_t; - -#endif - -#define zig_minInt_i8 INT8_MIN -#define zig_maxInt_i8 INT8_MAX -#define zig_minInt_u8 UINT8_C(0) -#define zig_maxInt_u8 UINT8_MAX -#define zig_minInt_i16 INT16_MIN -#define zig_maxInt_i16 INT16_MAX -#define zig_minInt_u16 UINT16_C(0) -#define zig_maxInt_u16 UINT16_MAX -#define zig_minInt_i32 INT32_MIN -#define zig_maxInt_i32 INT32_MAX -#define zig_minInt_u32 UINT32_C(0) -#define zig_maxInt_u32 UINT32_MAX -#define zig_minInt_i64 INT64_MIN -#define zig_maxInt_i64 INT64_MAX -#define zig_minInt_u64 UINT64_C(0) -#define zig_maxInt_u64 UINT64_MAX - -#define zig_intLimit(s, w, limit, bits) zig_shr_##s##w(zig_##limit##Int_##s##w, w - (bits)) -#define zig_minInt_i(w, bits) zig_intLimit(i, w, min, bits) -#define zig_maxInt_i(w, bits) zig_intLimit(i, w, max, bits) -#define zig_minInt_u(w, bits) zig_intLimit(u, w, min, bits) -#define zig_maxInt_u(w, bits) zig_intLimit(u, w, max, bits) - -#define zig_operator(Type, RhsType, operation, operator) \ - static inline Type zig_##operation(Type lhs, RhsType rhs) { \ - return lhs operator rhs; \ - } -#define zig_basic_operator(Type, operation, operator) \ - zig_operator(Type, Type, operation, operator) -#define zig_shift_operator(Type, operation, operator) \ - zig_operator(Type, uint8_t, operation, operator) -#define zig_int_helpers(w, PromotedUnsigned) \ - zig_basic_operator(uint##w##_t, and_u##w, &) \ - zig_basic_operator( int##w##_t, and_i##w, &) \ - zig_basic_operator(uint##w##_t, or_u##w, |) \ - zig_basic_operator( int##w##_t, or_i##w, |) \ - zig_basic_operator(uint##w##_t, xor_u##w, ^) \ - zig_basic_operator( int##w##_t, xor_i##w, ^) \ - zig_shift_operator(uint##w##_t, shl_u##w, <<) \ - zig_shift_operator( int##w##_t, shl_i##w, <<) \ - zig_shift_operator(uint##w##_t, shr_u##w, >>) \ -\ - static inline int##w##_t zig_shr_i##w(int##w##_t lhs, uint8_t rhs) { \ - int##w##_t sign_mask = lhs < INT##w##_C(0) ? -INT##w##_C(1) : INT##w##_C(0); \ - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ - } \ -\ - static inline uint##w##_t zig_not_u##w(uint##w##_t val, uint8_t bits) { \ - return val ^ zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_not_i##w(int##w##_t val, uint8_t bits) { \ - (void)bits; \ - return ~val; \ - } \ -\ - static inline uint##w##_t zig_wrap_u##w(uint##w##_t val, uint8_t bits) { \ - return val & zig_maxInt_u(w, bits); \ - } \ -\ - static inline int##w##_t zig_wrap_i##w(int##w##_t val, uint8_t bits) { \ - return (val & UINT##w##_C(1) << (bits - UINT8_C(1))) != 0 \ - ? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_abs_i##w(int##w##_t val) { \ - return (val < 0) ? -(uint##w##_t)val : (uint##w##_t)val; \ - } \ -\ - zig_basic_operator(uint##w##_t, div_floor_u##w, /) \ -\ - static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \ - return lhs / rhs + (lhs % rhs != INT##w##_C(0) ? zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ - } \ -\ - zig_basic_operator(uint##w##_t, mod_u##w, %) \ -\ - static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \ - int##w##_t rem = lhs % rhs; \ - return rem + (rem != INT##w##_C(0) ? rhs & zig_shr_i##w(lhs ^ rhs, UINT8_C(w) - UINT8_C(1)) : INT##w##_C(0)); \ - } \ -\ - static inline uint##w##_t zig_shlw_u##w(uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ - } \ -\ - static inline int##w##_t zig_shlw_i##w(int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)zig_shl_u##w((uint##w##_t)lhs, rhs), bits); \ - } \ -\ - static inline uint##w##_t zig_addw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs + rhs, bits); \ - } \ -\ - static inline int##w##_t zig_addw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs + (uint##w##_t)rhs), bits); \ - } \ -\ - static inline uint##w##_t zig_subw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w(lhs - rhs, bits); \ - } \ -\ - static inline int##w##_t zig_subw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs - (uint##w##_t)rhs), bits); \ - } \ -\ - static inline uint##w##_t zig_mulw_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - return zig_wrap_u##w((PromotedUnsigned)lhs * rhs, bits); \ - } \ -\ - static inline int##w##_t zig_mulw_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - return zig_wrap_i##w((int##w##_t)((uint##w##_t)lhs * (uint##w##_t)rhs), bits); \ - } -#if UINT8_MAX <= UINT_MAX -zig_int_helpers(8, unsigned int) -#elif UINT8_MAX <= ULONG_MAX -zig_int_helpers(8, unsigned long) -#elif UINT8_MAX <= ULLONG_MAX -zig_int_helpers(8, unsigned long long) -#else -zig_int_helpers(8, uint8_t) -#endif -#if UINT16_MAX <= UINT_MAX -zig_int_helpers(16, unsigned int) -#elif UINT16_MAX <= ULONG_MAX -zig_int_helpers(16, unsigned long) -#elif UINT16_MAX <= ULLONG_MAX -zig_int_helpers(16, unsigned long long) -#else -zig_int_helpers(16, uint16_t) -#endif -#if UINT32_MAX <= UINT_MAX -zig_int_helpers(32, unsigned int) -#elif UINT32_MAX <= ULONG_MAX -zig_int_helpers(32, unsigned long) -#elif UINT32_MAX <= ULLONG_MAX -zig_int_helpers(32, unsigned long long) -#else -zig_int_helpers(32, uint32_t) -#endif -#if UINT64_MAX <= UINT_MAX -zig_int_helpers(64, unsigned int) -#elif UINT64_MAX <= ULONG_MAX -zig_int_helpers(64, unsigned long) -#elif UINT64_MAX <= ULLONG_MAX -zig_int_helpers(64, unsigned long long) -#else -zig_int_helpers(64, uint64_t) -#endif - -static inline bool zig_addo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - uint32_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); - return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); -#else - *res = zig_addw_u32(lhs, rhs, bits); - return *res < lhs; -#endif -} - -zig_extern int32_t __addosi4(int32_t lhs, int32_t rhs, int *overflow); -static inline bool zig_addo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - int32_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int32_t full_res = __addosi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); -} - -static inline bool zig_addo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - uint64_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); - return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); -#else - *res = zig_addw_u64(lhs, rhs, bits); - return *res < lhs; -#endif -} - -zig_extern int64_t __addodi4(int64_t lhs, int64_t rhs, int *overflow); -static inline bool zig_addo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - int64_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int64_t full_res = __addodi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); -} - -static inline bool zig_addo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - uint8_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); - return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); -#else - uint32_t full_res; - bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_addo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - int8_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); - return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); -#else - int32_t full_res; - bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_addo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - uint16_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); - return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); -#else - uint32_t full_res; - bool overflow = zig_addo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; - return overflow; -#endif -} - -static inline bool zig_addo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) || defined(zig_gcc) - int16_t full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); - return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); -#else - int32_t full_res; - bool overflow = zig_addo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; - return overflow; -#endif -} - -static inline bool zig_subo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - uint32_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); - return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); -#else - *res = zig_subw_u32(lhs, rhs, bits); - return *res > lhs; -#endif -} - -zig_extern int32_t __subosi4(int32_t lhs, int32_t rhs, int *overflow); -static inline bool zig_subo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - int32_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int32_t full_res = __subosi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); -} - -static inline bool zig_subo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - uint64_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); - return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); -#else - *res = zig_subw_u64(lhs, rhs, bits); - return *res > lhs; -#endif -} - -zig_extern int64_t __subodi4(int64_t lhs, int64_t rhs, int *overflow); -static inline bool zig_subo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - int64_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int64_t full_res = __subodi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); -} - -static inline bool zig_subo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - uint8_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); - return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); -#else - uint32_t full_res; - bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_subo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - int8_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); - return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); -#else - int32_t full_res; - bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_subo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - uint16_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); - return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); -#else - uint32_t full_res; - bool overflow = zig_subo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; - return overflow; -#endif -} - -static inline bool zig_subo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) || defined(zig_gcc) - int16_t full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); - return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); -#else - int32_t full_res; - bool overflow = zig_subo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; - return overflow; -#endif -} - -static inline bool zig_mulo_u32(uint32_t *res, uint32_t lhs, uint32_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - uint32_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u32(full_res, bits); - return overflow || full_res < zig_minInt_u(32, bits) || full_res > zig_maxInt_u(32, bits); -#else - *res = zig_mulw_u32(lhs, rhs, bits); - return rhs != UINT32_C(0) && lhs > zig_maxInt_u(32, bits) / rhs; -#endif -} - -zig_extern int32_t __mulosi4(int32_t lhs, int32_t rhs, int *overflow); -static inline bool zig_mulo_i32(int32_t *res, int32_t lhs, int32_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - int32_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int32_t full_res = __mulosi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i32(full_res, bits); - return overflow || full_res < zig_minInt_i(32, bits) || full_res > zig_maxInt_i(32, bits); -} - -static inline bool zig_mulo_u64(uint64_t *res, uint64_t lhs, uint64_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - uint64_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u64(full_res, bits); - return overflow || full_res < zig_minInt_u(64, bits) || full_res > zig_maxInt_u(64, bits); -#else - *res = zig_mulw_u64(lhs, rhs, bits); - return rhs != UINT64_C(0) && lhs > zig_maxInt_u(64, bits) / rhs; -#endif -} - -zig_extern int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); -static inline bool zig_mulo_i64(int64_t *res, int64_t lhs, int64_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - int64_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - int64_t full_res = __mulodi4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i64(full_res, bits); - return overflow || full_res < zig_minInt_i(64, bits) || full_res > zig_maxInt_i(64, bits); -} - -static inline bool zig_mulo_u8(uint8_t *res, uint8_t lhs, uint8_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - uint8_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u8(full_res, bits); - return overflow || full_res < zig_minInt_u(8, bits) || full_res > zig_maxInt_u(8, bits); -#else - uint32_t full_res; - bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_mulo_i8(int8_t *res, int8_t lhs, int8_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - int8_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i8(full_res, bits); - return overflow || full_res < zig_minInt_i(8, bits) || full_res > zig_maxInt_i(8, bits); -#else - int32_t full_res; - bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int8_t)full_res; - return overflow; -#endif -} - -static inline bool zig_mulo_u16(uint16_t *res, uint16_t lhs, uint16_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - uint16_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u16(full_res, bits); - return overflow || full_res < zig_minInt_u(16, bits) || full_res > zig_maxInt_u(16, bits); -#else - uint32_t full_res; - bool overflow = zig_mulo_u32(&full_res, lhs, rhs, bits); - *res = (uint16_t)full_res; - return overflow; -#endif -} - -static inline bool zig_mulo_i16(int16_t *res, int16_t lhs, int16_t rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) || defined(zig_gcc) - int16_t full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_i16(full_res, bits); - return overflow || full_res < zig_minInt_i(16, bits) || full_res > zig_maxInt_i(16, bits); -#else - int32_t full_res; - bool overflow = zig_mulo_i32(&full_res, lhs, rhs, bits); - *res = (int16_t)full_res; - return overflow; -#endif -} - -#define zig_int_builtins(w) \ - static inline bool zig_shlo_u##w(uint##w##_t *res, uint##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - *res = zig_shlw_u##w(lhs, rhs, bits); \ - return lhs > zig_maxInt_u(w, bits) >> rhs; \ - } \ -\ - static inline bool zig_shlo_i##w(int##w##_t *res, int##w##_t lhs, uint8_t rhs, uint8_t bits) { \ - *res = zig_shlw_i##w(lhs, rhs, bits); \ - int##w##_t mask = (int##w##_t)(UINT##w##_MAX << (bits - rhs - 1)); \ - return (lhs & mask) != INT##w##_C(0) && (lhs & mask) != mask; \ - } \ -\ - static inline uint##w##_t zig_shls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - if (rhs >= bits) return lhs != UINT##w##_C(0) ? zig_maxInt_u(w, bits) : lhs; \ - return zig_shlo_u##w(&res, lhs, (uint8_t)rhs, bits) ? zig_maxInt_u(w, bits) : res; \ - } \ -\ - static inline int##w##_t zig_shls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if ((uint##w##_t)rhs < (uint##w##_t)bits && !zig_shlo_i##w(&res, lhs, (uint8_t)rhs, bits)) return res; \ - return lhs < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_adds_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt_u(w, bits) : res; \ - } \ -\ - static inline int##w##_t zig_adds_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \ - return res >= INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_subs_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt_u(w, bits) : res; \ - } \ -\ - static inline int##w##_t zig_subs_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \ - return res >= INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } \ -\ - static inline uint##w##_t zig_muls_u##w(uint##w##_t lhs, uint##w##_t rhs, uint8_t bits) { \ - uint##w##_t res; \ - return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt_u(w, bits) : res; \ - } \ -\ - static inline int##w##_t zig_muls_i##w(int##w##_t lhs, int##w##_t rhs, uint8_t bits) { \ - int##w##_t res; \ - if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ - return (lhs ^ rhs) < INT##w##_C(0) ? zig_minInt_i(w, bits) : zig_maxInt_i(w, bits); \ - } -zig_int_builtins(8) -zig_int_builtins(16) -zig_int_builtins(32) -zig_int_builtins(64) - -#define zig_builtin8(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin8; - -#define zig_builtin16(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin16; - -#if INT_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin32; -#elif LONG_MIN <= INT32_MIN -#define zig_builtin32(name, val) __builtin_##name##l(val) -typedef unsigned long zig_Builtin32; -#endif - -#if INT_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name(val) -typedef unsigned int zig_Builtin64; -#elif LONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##l(val) -typedef unsigned long zig_Builtin64; -#elif LLONG_MIN <= INT64_MIN -#define zig_builtin64(name, val) __builtin_##name##ll(val) -typedef unsigned long long zig_Builtin64; -#endif - -static inline uint8_t zig_byte_swap_u8(uint8_t val, uint8_t bits) { - return zig_wrap_u8(val >> (8 - bits), bits); -} - -static inline int8_t zig_byte_swap_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_byte_swap_u8((uint8_t)val, bits), bits); -} - -static inline uint16_t zig_byte_swap_u16(uint16_t val, uint8_t bits) { - uint16_t full_res; -#if zig_has_builtin(bswap16) || defined(zig_gcc) - full_res = __builtin_bswap16(val); -#else - full_res = (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_byte_swap_u8((uint8_t)(val >> 8), 8) >> 0; -#endif - return zig_wrap_u16(full_res >> (16 - bits), bits); -} - -static inline int16_t zig_byte_swap_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_byte_swap_u16((uint16_t)val, bits), bits); -} - -static inline uint32_t zig_byte_swap_u32(uint32_t val, uint8_t bits) { - uint32_t full_res; -#if zig_has_builtin(bswap32) || defined(zig_gcc) - full_res = __builtin_bswap32(val); -#else - full_res = (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_byte_swap_u16((uint16_t)(val >> 16), 16) >> 0; -#endif - return zig_wrap_u32(full_res >> (32 - bits), bits); -} - -static inline int32_t zig_byte_swap_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_byte_swap_u32((uint32_t)val, bits), bits); -} - -static inline uint64_t zig_byte_swap_u64(uint64_t val, uint8_t bits) { - uint64_t full_res; -#if zig_has_builtin(bswap64) || defined(zig_gcc) - full_res = __builtin_bswap64(val); -#else - full_res = (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_byte_swap_u32((uint32_t)(val >> 32), 32) >> 0; -#endif - return zig_wrap_u64(full_res >> (64 - bits), bits); -} - -static inline int64_t zig_byte_swap_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_byte_swap_u64((uint64_t)val, bits), bits); -} - -static inline uint8_t zig_bit_reverse_u8(uint8_t val, uint8_t bits) { - uint8_t full_res; -#if zig_has_builtin(bitreverse8) - full_res = __builtin_bitreverse8(val); -#else - static uint8_t const lut[0x10] = { - 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, - 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf - }; - full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; -#endif - return zig_wrap_u8(full_res >> (8 - bits), bits); -} - -static inline int8_t zig_bit_reverse_i8(int8_t val, uint8_t bits) { - return zig_wrap_i8((int8_t)zig_bit_reverse_u8((uint8_t)val, bits), bits); -} - -static inline uint16_t zig_bit_reverse_u16(uint16_t val, uint8_t bits) { - uint16_t full_res; -#if zig_has_builtin(bitreverse16) - full_res = __builtin_bitreverse16(val); -#else - full_res = (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 0), 8) << 8 | - (uint16_t)zig_bit_reverse_u8((uint8_t)(val >> 8), 8) >> 0; -#endif - return zig_wrap_u16(full_res >> (16 - bits), bits); -} - -static inline int16_t zig_bit_reverse_i16(int16_t val, uint8_t bits) { - return zig_wrap_i16((int16_t)zig_bit_reverse_u16((uint16_t)val, bits), bits); -} - -static inline uint32_t zig_bit_reverse_u32(uint32_t val, uint8_t bits) { - uint32_t full_res; -#if zig_has_builtin(bitreverse32) - full_res = __builtin_bitreverse32(val); -#else - full_res = (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 0), 16) << 16 | - (uint32_t)zig_bit_reverse_u16((uint16_t)(val >> 16), 16) >> 0; -#endif - return zig_wrap_u32(full_res >> (32 - bits), bits); -} - -static inline int32_t zig_bit_reverse_i32(int32_t val, uint8_t bits) { - return zig_wrap_i32((int32_t)zig_bit_reverse_u32((uint32_t)val, bits), bits); -} - -static inline uint64_t zig_bit_reverse_u64(uint64_t val, uint8_t bits) { - uint64_t full_res; -#if zig_has_builtin(bitreverse64) - full_res = __builtin_bitreverse64(val); -#else - full_res = (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 0), 32) << 32 | - (uint64_t)zig_bit_reverse_u32((uint32_t)(val >> 32), 32) >> 0; -#endif - return zig_wrap_u64(full_res >> (64 - bits), bits); -} - -static inline int64_t zig_bit_reverse_i64(int64_t val, uint8_t bits) { - return zig_wrap_i64((int64_t)zig_bit_reverse_u64((uint64_t)val, bits), bits); -} - -#define zig_builtin_popcount_common(w) \ - static inline uint8_t zig_popcount_i##w(int##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w((uint##w##_t)val, bits); \ - } -#if zig_has_builtin(popcount) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ - (void)bits; \ - return zig_builtin##w(popcount, val); \ - } \ -\ - zig_builtin_popcount_common(w) -#else -#define zig_builtin_popcount(w) \ - static inline uint8_t zig_popcount_u##w(uint##w##_t val, uint8_t bits) { \ - (void)bits; \ - uint##w##_t temp = val - ((val >> 1) & (UINT##w##_MAX / 3)); \ - temp = (temp & (UINT##w##_MAX / 5)) + ((temp >> 2) & (UINT##w##_MAX / 5)); \ - temp = (temp + (temp >> 4)) & (UINT##w##_MAX / 17); \ - return temp * (UINT##w##_MAX / 255) >> (UINT8_C(w) - UINT8_C(8)); \ - } \ -\ - zig_builtin_popcount_common(w) -#endif -zig_builtin_popcount(8) -zig_builtin_popcount(16) -zig_builtin_popcount(32) -zig_builtin_popcount(64) - -#define zig_builtin_ctz_common(w) \ - static inline uint8_t zig_ctz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w((uint##w##_t)val, bits); \ - } -#if zig_has_builtin(ctz) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(ctz, val); \ - } \ -\ - zig_builtin_ctz_common(w) -#else -#define zig_builtin_ctz(w) \ - static inline uint8_t zig_ctz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_popcount_u##w(zig_not_u##w(val, bits) & zig_subw_u##w(val, 1, bits), bits); \ - } \ -\ - zig_builtin_ctz_common(w) -#endif -zig_builtin_ctz(8) -zig_builtin_ctz(16) -zig_builtin_ctz(32) -zig_builtin_ctz(64) - -#define zig_builtin_clz_common(w) \ - static inline uint8_t zig_clz_i##w(int##w##_t val, uint8_t bits) { \ - return zig_clz_u##w((uint##w##_t)val, bits); \ - } -#if zig_has_builtin(clz) || defined(zig_gcc) || defined(zig_tinyc) -#define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - if (val == 0) return bits; \ - return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ - } \ -\ - zig_builtin_clz_common(w) -#else -#define zig_builtin_clz(w) \ - static inline uint8_t zig_clz_u##w(uint##w##_t val, uint8_t bits) { \ - return zig_ctz_u##w(zig_bit_reverse_u##w(val, bits), bits); \ - } \ -\ - zig_builtin_clz_common(w) -#endif -zig_builtin_clz(8) -zig_builtin_clz(16) -zig_builtin_clz(32) -zig_builtin_clz(64) - -/* ======================== 128-bit Integer Support ========================= */ - -#if !defined(zig_has_int128) -# if defined(__SIZEOF_INT128__) -# define zig_has_int128 1 -# else -# define zig_has_int128 0 -# endif -#endif - -#if zig_has_int128 - -typedef unsigned __int128 zig_u128; -typedef signed __int128 zig_i128; - -#define zig_make_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) -#define zig_make_i128(hi, lo) ((zig_i128)zig_make_u128(hi, lo)) -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#define zig_hi_u128(val) ((uint64_t)((val) >> 64)) -#define zig_lo_u128(val) ((uint64_t)((val) >> 0)) -#define zig_hi_i128(val) (( int64_t)((val) >> 64)) -#define zig_lo_i128(val) ((uint64_t)((val) >> 0)) -#define zig_bitCast_u128(val) ((zig_u128)(val)) -#define zig_bitCast_i128(val) ((zig_i128)(val)) -#define zig_cmp_int128(Type) \ - static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return (lhs > rhs) - (lhs < rhs); \ - } -#define zig_bit_int128(Type, operation, operator) \ - static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return lhs operator rhs; \ - } - -#else /* zig_has_int128 */ - -#if zig_little_endian -typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; -typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; -#else -typedef struct { zig_align(16) uint64_t hi; uint64_t lo; } zig_u128; -typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128; -#endif - -#define zig_make_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) -#define zig_make_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) - -#if defined(zig_msvc) /* MSVC doesn't allow struct literals in constant expressions */ -#define zig_init_u128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#define zig_init_i128(hi, lo) { .h##i = (hi), .l##o = (lo) } -#else /* But non-MSVC doesn't like the unprotected commas */ -#define zig_init_u128(hi, lo) zig_make_u128(hi, lo) -#define zig_init_i128(hi, lo) zig_make_i128(hi, lo) -#endif -#define zig_hi_u128(val) ((val).hi) -#define zig_lo_u128(val) ((val).lo) -#define zig_hi_i128(val) ((val).hi) -#define zig_lo_i128(val) ((val).lo) -#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo) -#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo) -#define zig_cmp_int128(Type) \ - static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return (lhs.hi == rhs.hi) \ - ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \ - : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \ - } -#define zig_bit_int128(Type, operation, operator) \ - static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ - } - -#endif /* zig_has_int128 */ - -#define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64) -#define zig_maxInt_u128 zig_make_u128(zig_maxInt_u64, zig_maxInt_u64) -#define zig_minInt_i128 zig_make_i128(zig_minInt_i64, zig_minInt_u64) -#define zig_maxInt_i128 zig_make_i128(zig_maxInt_i64, zig_maxInt_u64) - -zig_cmp_int128(u128) -zig_cmp_int128(i128) - -zig_bit_int128(u128, and, &) -zig_bit_int128(i128, and, &) - -zig_bit_int128(u128, or, |) -zig_bit_int128(i128, or, |) - -zig_bit_int128(u128, xor, ^) -zig_bit_int128(i128, xor, ^) - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs); - -#if zig_has_int128 - -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return val ^ zig_maxInt_u(128, bits); -} - -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - (void)bits; - return ~val; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - return lhs >> rhs; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - return lhs << rhs; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - zig_i128 sign_mask = lhs < zig_make_i128(0, 0) ? -zig_make_i128(0, 1) : zig_make_i128(0, 0); - return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - return lhs << rhs; -} - -static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { - return lhs + rhs; -} - -static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { - return lhs + rhs; -} - -static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { - return lhs - rhs; -} - -static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { - return lhs - rhs; -} - -static inline zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return lhs * rhs; -} - -static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { - return lhs * rhs; -} - -static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { - return lhs / rhs; -} - -static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { - return lhs / rhs; -} - -static inline zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { - return lhs % rhs; -} - -static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { - return lhs % rhs; -} - -#else /* zig_has_int128 */ - -static inline zig_u128 zig_not_u128(zig_u128 val, uint8_t bits) { - return (zig_u128){ .hi = zig_not_u64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_i128 zig_not_i128(zig_i128 val, uint8_t bits) { - return (zig_i128){ .hi = zig_not_i64(val.hi, bits - UINT8_C(64)), .lo = zig_not_u64(val.lo, UINT8_C(64)) }; -} - -static inline zig_u128 zig_shr_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = zig_minInt_u64, .lo = lhs.hi >> (rhs - UINT8_C(64)) }; - return (zig_u128){ .hi = lhs.hi >> rhs, .lo = lhs.hi << (UINT8_C(64) - rhs) | lhs.lo >> rhs }; -} - -static inline zig_u128 zig_shl_u128(zig_u128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_u128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_i128 zig_shr_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = zig_shr_i64(lhs.hi, 63), .lo = zig_shr_i64(lhs.hi, (rhs - UINT8_C(64))) }; - return (zig_i128){ .hi = zig_shr_i64(lhs.hi, rhs), .lo = lhs.lo >> rhs | (uint64_t)lhs.hi << (UINT8_C(64) - rhs) }; -} - -static inline zig_i128 zig_shl_i128(zig_i128 lhs, uint8_t rhs) { - if (rhs == UINT8_C(0)) return lhs; - if (rhs >= UINT8_C(64)) return (zig_i128){ .hi = lhs.lo << (rhs - UINT8_C(64)), .lo = zig_minInt_u64 }; - return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (UINT8_C(64) - rhs), .lo = lhs.lo << rhs }; -} - -static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { - zig_u128 res; - res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64); - return res; -} - -static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { - zig_i128 res; - res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, 64); - return res; -} - -static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { - zig_u128 res; - res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64); - return res; -} - -static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { - zig_i128 res; - res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, 64); - return res; -} - -zig_extern zig_i128 __multi3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { - return __multi3(lhs, rhs); -} - -static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs))); -} - -zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { - return __udivti3(lhs, rhs); -} - -zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { - return __divti3(lhs, rhs); -} - -zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs); -static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { - return __umodti3(lhs, rhs); -} - -zig_extern zig_i128 __modti3(zig_i128 lhs, zig_i128 rhs); -static zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { - return __modti3(lhs, rhs); -} - -#endif /* zig_has_int128 */ - -#define zig_div_floor_u128 zig_div_trunc_u128 - -static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { - zig_i128 rem = zig_rem_i128(lhs, rhs); - int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) - ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(zig_div_trunc_i128(lhs, rhs), zig_make_i128(mask, (uint64_t)mask)); -} - -#define zig_mod_u128 zig_rem_u128 - -static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { - zig_i128 rem = zig_rem_i128(lhs, rhs); - int64_t mask = zig_or_u64((uint64_t)zig_hi_i128(rem), zig_lo_i128(rem)) != UINT64_C(0) - ? zig_shr_i64(zig_xor_i64(zig_hi_i128(lhs), zig_hi_i128(rhs)), UINT8_C(63)) : INT64_C(0); - return zig_add_i128(rem, zig_and_i128(rhs, zig_make_i128(mask, (uint64_t)mask))); -} - -static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_cmp_u128(lhs, rhs) < INT32_C(0) ? lhs : rhs; -} - -static inline zig_i128 zig_min_i128(zig_i128 lhs, zig_i128 rhs) { - return zig_cmp_i128(lhs, rhs) < INT32_C(0) ? lhs : rhs; -} - -static inline zig_u128 zig_max_u128(zig_u128 lhs, zig_u128 rhs) { - return zig_cmp_u128(lhs, rhs) > INT32_C(0) ? lhs : rhs; -} - -static inline zig_i128 zig_max_i128(zig_i128 lhs, zig_i128 rhs) { - return zig_cmp_i128(lhs, rhs) > INT32_C(0) ? lhs : rhs; -} - -static inline zig_u128 zig_wrap_u128(zig_u128 val, uint8_t bits) { - return zig_and_u128(val, zig_maxInt_u(128, bits)); -} - -static inline zig_i128 zig_wrap_i128(zig_i128 val, uint8_t bits) { - if (bits > UINT8_C(64)) return zig_make_i128(zig_wrap_i64(zig_hi_i128(val), bits - UINT8_C(64)), zig_lo_i128(val)); - int64_t lo = zig_wrap_i64((int64_t)zig_lo_i128(val), bits); - return zig_make_i128(zig_shr_i64(lo, 63), (uint64_t)lo); -} - -static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); -} - -static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits); -} - -static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); -} - -static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); -} - -static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); -} - -static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); -} - -static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); -} - -static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits); -} - -static inline zig_u128 zig_abs_i128(zig_i128 val) { - zig_i128 tmp = zig_shr_i128(val, 127); - return zig_bitCast_u128(zig_sub_i128(zig_xor_i128(val, tmp), tmp)); -} - -#if zig_has_int128 - -static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) - zig_u128 full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); - return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); -#else - *res = zig_addw_u128(lhs, rhs, bits); - return *res < lhs; -#endif -} - -zig_extern zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, int *overflow); -static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { -#if zig_has_builtin(add_overflow) - zig_i128 full_res; - bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i128(full_res, bits); - return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); -} - -static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) - zig_u128 full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); - return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); -#else - *res = zig_subw_u128(lhs, rhs, bits); - return *res > lhs; -#endif -} - -zig_extern zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, int *overflow); -static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { -#if zig_has_builtin(sub_overflow) - zig_i128 full_res; - bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i128(full_res, bits); - return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); -} - -static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) - zig_u128 full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); - *res = zig_wrap_u128(full_res, bits); - return overflow || full_res < zig_minInt_u(128, bits) || full_res > zig_maxInt_u(128, bits); -#else - *res = zig_mulw_u128(lhs, rhs, bits); - return rhs != zig_make_u128(0, 0) && lhs > zig_maxInt_u(128, bits) / rhs; -#endif -} - -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); -static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { -#if zig_has_builtin(mul_overflow) - zig_i128 full_res; - bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); -#else - int overflow_int; - zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0; -#endif - *res = zig_wrap_i128(full_res, bits); - return overflow || full_res < zig_minInt_i(128, bits) || full_res > zig_maxInt_i(128, bits); -} - -#else /* zig_has_int128 */ - -static inline bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_addo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_u64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); -} - -static inline bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_addo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_addo_i64(&res->hi, hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); -} - -static inline bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - uint64_t hi; - bool overflow = zig_subo_u64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_u64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); -} - -static inline bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int64_t hi; - bool overflow = zig_subo_i64(&hi, lhs.hi, rhs.hi, bits - 64); - return overflow ^ zig_subo_i64(&res->hi, hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, 64), bits - 64); -} - -static inline bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - *res = zig_mulw_u128(lhs, rhs, bits); - return zig_cmp_u128(*res, zig_make_u128(0, 0)) != INT32_C(0) && - zig_cmp_u128(lhs, zig_div_trunc_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); -} - -zig_extern zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, int *overflow); -static inline bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - int overflow_int; - zig_i128 full_res = __muloti4(lhs, rhs, &overflow_int); - bool overflow = overflow_int != 0 || - zig_cmp_i128(full_res, zig_minInt_i(128, bits)) < INT32_C(0) || - zig_cmp_i128(full_res, zig_maxInt_i(128, bits)) > INT32_C(0); - *res = zig_wrap_i128(full_res, bits); - return overflow; -} - -#endif /* zig_has_int128 */ - -static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8_t bits) { - *res = zig_shlw_u128(lhs, rhs, bits); - return zig_cmp_u128(lhs, zig_shr_u128(zig_maxInt_u(128, bits), rhs)) > INT32_C(0); -} - -static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) { - *res = zig_shlw_i128(lhs, rhs, bits); - zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1))); - return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) && - zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0); -} - -static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - zig_u128 res; - if (zig_cmp_u128(rhs, zig_make_u128(0, bits)) >= INT32_C(0)) - return zig_cmp_u128(lhs, zig_make_u128(0, 0)) != INT32_C(0) ? zig_maxInt_u(128, bits) : lhs; - return zig_shlo_u128(&res, lhs, (uint8_t)zig_lo_u128(rhs), bits) ? zig_maxInt_u(128, bits) : res; -} - -static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - zig_i128 res; - if (zig_cmp_u128(zig_bitCast_u128(rhs), zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_i128(rhs), bits)) return res; - return zig_cmp_i128(lhs, zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); -} - -static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - zig_u128 res; - return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt_u(128, bits) : res; -} - -static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - zig_i128 res; - if (!zig_addo_i128(&res, lhs, rhs, bits)) return res; - return zig_cmp_i128(res, zig_make_i128(0, 0)) >= INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); -} - -static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - zig_u128 res; - return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt_u(128, bits) : res; -} - -static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - zig_i128 res; - if (!zig_subo_i128(&res, lhs, rhs, bits)) return res; - return zig_cmp_i128(res, zig_make_i128(0, 0)) >= INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); -} - -static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) { - zig_u128 res; - return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt_u(128, bits) : res; -} - -static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) { - zig_i128 res; - if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res; - return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits); -} - -static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) { - if (bits <= UINT8_C(64)) return zig_clz_u64(zig_lo_u128(val), bits); - if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - UINT8_C(64)); - return zig_clz_u64(zig_lo_u128(val), UINT8_C(64)) + (bits - UINT8_C(64)); -} - -static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) { - return zig_clz_u128(zig_bitCast_u128(val), bits); -} - -static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) { - if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), UINT8_C(64)); - return zig_ctz_u64(zig_hi_u128(val), bits - UINT8_C(64)) + UINT8_C(64); -} - -static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) { - return zig_ctz_u128(zig_bitCast_u128(val), bits); -} - -static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) { - return zig_popcount_u64(zig_hi_u128(val), bits - UINT8_C(64)) + - zig_popcount_u64(zig_lo_u128(val), UINT8_C(64)); -} - -static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) { - return zig_popcount_u128(zig_bitCast_u128(val), bits); -} - -static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) { - zig_u128 full_res; -#if zig_has_builtin(bswap128) - full_res = __builtin_bswap128(val); -#else - full_res = zig_make_u128(zig_byte_swap_u64(zig_lo_u128(val), UINT8_C(64)), - zig_byte_swap_u64(zig_hi_u128(val), UINT8_C(64))); -#endif - return zig_shr_u128(full_res, UINT8_C(128) - bits); -} - -static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits)); -} - -static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) { - return zig_shr_u128(zig_make_u128(zig_bit_reverse_u64(zig_lo_u128(val), UINT8_C(64)), - zig_bit_reverse_u64(zig_hi_u128(val), UINT8_C(64))), - UINT8_C(128) - bits); -} - -static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { - return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits)); -} - -/* ========================== Big Integer Support =========================== */ - -static inline uint16_t zig_int_bytes(uint16_t bits) { - uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; - uint16_t alignment = ZIG_TARGET_MAX_INT_ALIGNMENT; - while (alignment / 2 >= bytes) alignment /= 2; - return (bytes + alignment - 1) / alignment * alignment; -} - -static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - bool do_signed = is_signed; - uint16_t remaining_bytes = zig_int_bytes(bits); - -#if zig_little_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { - int32_t limb_cmp; - -#if zig_little_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - if (do_signed) { - zig_i128 lhs_limb; - zig_i128 rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); - do_signed = false; - } else { - zig_u128 lhs_limb; - zig_u128 rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); - } - - if (limb_cmp != 0) return limb_cmp; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - if (do_signed) { - int64_t lhs_limb; - int64_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - do_signed = false; - } else { - uint64_t lhs_limb; - uint64_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - } - - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - if (do_signed) { - int32_t lhs_limb; - int32_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - do_signed = false; - } else { - uint32_t lhs_limb; - uint32_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - } - - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - if (do_signed) { - int16_t lhs_limb; - int16_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - do_signed = false; - } else { - uint16_t lhs_limb; - uint16_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - } - - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - if (do_signed) { - int8_t lhs_limb; - int8_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - do_signed = false; - } else { - uint8_t lhs_limb; - uint8_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); - } - - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return 0; -} - -static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - uint8_t *res_bytes = res; - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - (void)is_signed; - - while (remaining_bytes >= 128 / CHAR_BIT) { - zig_u128 res_limb; - zig_u128 lhs_limb; - zig_u128 rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_and_u128(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 128 / CHAR_BIT; - byte_offset += 128 / CHAR_BIT; - } - - while (remaining_bytes >= 64 / CHAR_BIT) { - uint64_t res_limb; - uint64_t lhs_limb; - uint64_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_and_u64(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 64 / CHAR_BIT; - byte_offset += 64 / CHAR_BIT; - } - - while (remaining_bytes >= 32 / CHAR_BIT) { - uint32_t res_limb; - uint32_t lhs_limb; - uint32_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_and_u32(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 32 / CHAR_BIT; - byte_offset += 32 / CHAR_BIT; - } - - while (remaining_bytes >= 16 / CHAR_BIT) { - uint16_t res_limb; - uint16_t lhs_limb; - uint16_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_and_u16(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 16 / CHAR_BIT; - byte_offset += 16 / CHAR_BIT; - } - - while (remaining_bytes >= 8 / CHAR_BIT) { - uint8_t res_limb; - uint8_t lhs_limb; - uint8_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_and_u8(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 8 / CHAR_BIT; - byte_offset += 8 / CHAR_BIT; - } -} - -static inline void zig_or_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - uint8_t *res_bytes = res; - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - (void)is_signed; - - while (remaining_bytes >= 128 / CHAR_BIT) { - zig_u128 res_limb; - zig_u128 lhs_limb; - zig_u128 rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_or_u128(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 128 / CHAR_BIT; - byte_offset += 128 / CHAR_BIT; - } - - while (remaining_bytes >= 64 / CHAR_BIT) { - uint64_t res_limb; - uint64_t lhs_limb; - uint64_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_or_u64(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 64 / CHAR_BIT; - byte_offset += 64 / CHAR_BIT; - } - - while (remaining_bytes >= 32 / CHAR_BIT) { - uint32_t res_limb; - uint32_t lhs_limb; - uint32_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_or_u32(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 32 / CHAR_BIT; - byte_offset += 32 / CHAR_BIT; - } - - while (remaining_bytes >= 16 / CHAR_BIT) { - uint16_t res_limb; - uint16_t lhs_limb; - uint16_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_or_u16(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 16 / CHAR_BIT; - byte_offset += 16 / CHAR_BIT; - } - - while (remaining_bytes >= 8 / CHAR_BIT) { - uint8_t res_limb; - uint8_t lhs_limb; - uint8_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_or_u8(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 8 / CHAR_BIT; - byte_offset += 8 / CHAR_BIT; - } -} - -static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - uint8_t *res_bytes = res; - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - (void)is_signed; - - while (remaining_bytes >= 128 / CHAR_BIT) { - zig_u128 res_limb; - zig_u128 lhs_limb; - zig_u128 rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_xor_u128(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 128 / CHAR_BIT; - byte_offset += 128 / CHAR_BIT; - } - - while (remaining_bytes >= 64 / CHAR_BIT) { - uint64_t res_limb; - uint64_t lhs_limb; - uint64_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_xor_u64(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 64 / CHAR_BIT; - byte_offset += 64 / CHAR_BIT; - } - - while (remaining_bytes >= 32 / CHAR_BIT) { - uint32_t res_limb; - uint32_t lhs_limb; - uint32_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_xor_u32(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 32 / CHAR_BIT; - byte_offset += 32 / CHAR_BIT; - } - - while (remaining_bytes >= 16 / CHAR_BIT) { - uint16_t res_limb; - uint16_t lhs_limb; - uint16_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_xor_u16(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 16 / CHAR_BIT; - byte_offset += 16 / CHAR_BIT; - } - - while (remaining_bytes >= 8 / CHAR_BIT) { - uint8_t res_limb; - uint8_t lhs_limb; - uint8_t rhs_limb; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - res_limb = zig_xor_u8(lhs_limb, rhs_limb); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - - remaining_bytes -= 8 / CHAR_BIT; - byte_offset += 8 / CHAR_BIT; - } -} - -static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - uint8_t *res_bytes = res; - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); - bool overflow = false; - -#if zig_big_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { - uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - if (remaining_bytes == 128 / CHAR_BIT && is_signed) { - zig_i128 res_limb; - zig_i128 tmp_limb; - zig_i128 lhs_limb; - zig_i128 rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_i128(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_i128(&res_limb, tmp_limb, zig_make_i128(INT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - zig_u128 res_limb; - zig_u128 tmp_limb; - zig_u128 lhs_limb; - zig_u128 rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_u128(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_u128(&res_limb, tmp_limb, zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { - uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - if (remaining_bytes == 64 / CHAR_BIT && is_signed) { - int64_t res_limb; - int64_t tmp_limb; - int64_t lhs_limb; - int64_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_i64(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_i64(&res_limb, tmp_limb, overflow ? INT64_C(1) : INT64_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint64_t res_limb; - uint64_t tmp_limb; - uint64_t lhs_limb; - uint64_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_u64(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_u64(&res_limb, tmp_limb, overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { - uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - if (remaining_bytes == 32 / CHAR_BIT && is_signed) { - int32_t res_limb; - int32_t tmp_limb; - int32_t lhs_limb; - int32_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_i32(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_i32(&res_limb, tmp_limb, overflow ? INT32_C(1) : INT32_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint32_t res_limb; - uint32_t tmp_limb; - uint32_t lhs_limb; - uint32_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_u32(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_u32(&res_limb, tmp_limb, overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { - uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - if (remaining_bytes == 16 / CHAR_BIT && is_signed) { - int16_t res_limb; - int16_t tmp_limb; - int16_t lhs_limb; - int16_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_i16(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_i16(&res_limb, tmp_limb, overflow ? INT16_C(1) : INT16_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint16_t res_limb; - uint16_t tmp_limb; - uint16_t lhs_limb; - uint16_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_u16(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_u16(&res_limb, tmp_limb, overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { - uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - if (remaining_bytes == 8 / CHAR_BIT && is_signed) { - int8_t res_limb; - int8_t tmp_limb; - int8_t lhs_limb; - int8_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_i8(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_i8(&res_limb, tmp_limb, overflow ? INT8_C(1) : INT8_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint8_t res_limb; - uint8_t tmp_limb; - uint8_t lhs_limb; - uint8_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_addo_u8(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_addo_u8(&res_limb, tmp_limb, overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return overflow; -} - -static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - uint8_t *res_bytes = res; - const uint8_t *lhs_bytes = lhs; - const uint8_t *rhs_bytes = rhs; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); - bool overflow = false; - -#if zig_big_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { - uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - if (remaining_bytes == 128 / CHAR_BIT && is_signed) { - zig_i128 res_limb; - zig_i128 tmp_limb; - zig_i128 lhs_limb; - zig_i128 rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_i128(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_i128(&res_limb, tmp_limb, zig_make_i128(INT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - zig_u128 res_limb; - zig_u128 tmp_limb; - zig_u128 lhs_limb; - zig_u128 rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_u128(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_u128(&res_limb, tmp_limb, zig_make_u128(UINT64_C(0), overflow ? UINT64_C(1) : UINT64_C(0)), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { - uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - if (remaining_bytes == 64 / CHAR_BIT && is_signed) { - int64_t res_limb; - int64_t tmp_limb; - int64_t lhs_limb; - int64_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_i64(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_i64(&res_limb, tmp_limb, overflow ? INT64_C(1) : INT64_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint64_t res_limb; - uint64_t tmp_limb; - uint64_t lhs_limb; - uint64_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_u64(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_u64(&res_limb, tmp_limb, overflow ? UINT64_C(1) : UINT64_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { - uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - if (remaining_bytes == 32 / CHAR_BIT && is_signed) { - int32_t res_limb; - int32_t tmp_limb; - int32_t lhs_limb; - int32_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_i32(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_i32(&res_limb, tmp_limb, overflow ? INT32_C(1) : INT32_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint32_t res_limb; - uint32_t tmp_limb; - uint32_t lhs_limb; - uint32_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_u32(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_u32(&res_limb, tmp_limb, overflow ? UINT32_C(1) : UINT32_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { - uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - if (remaining_bytes == 16 / CHAR_BIT && is_signed) { - int16_t res_limb; - int16_t tmp_limb; - int16_t lhs_limb; - int16_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_i16(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_i16(&res_limb, tmp_limb, overflow ? INT16_C(1) : INT16_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint16_t res_limb; - uint16_t tmp_limb; - uint16_t lhs_limb; - uint16_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_u16(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_u16(&res_limb, tmp_limb, overflow ? UINT16_C(1) : UINT16_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { - uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); - -#if zig_big_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - if (remaining_bytes == 8 / CHAR_BIT && is_signed) { - int8_t res_limb; - int8_t tmp_limb; - int8_t lhs_limb; - int8_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_i8(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_i8(&res_limb, tmp_limb, overflow ? INT8_C(1) : INT8_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } else { - uint8_t res_limb; - uint8_t tmp_limb; - uint8_t lhs_limb; - uint8_t rhs_limb; - bool limb_overflow; - - memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); - memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); - limb_overflow = zig_subo_u8(&tmp_limb, lhs_limb, rhs_limb, limb_bits); - overflow = limb_overflow ^ zig_subo_u8(&res_limb, tmp_limb, overflow ? UINT8_C(1) : UINT8_C(0), limb_bits); - memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb)); - } - - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return overflow; -} - -static inline void zig_addw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - (void)zig_addo_big(res, lhs, rhs, is_signed, bits); -} - -static inline void zig_subw_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - (void)zig_subo_big(res, lhs, rhs, is_signed, bits); -} - -zig_extern void __udivei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_div_trunc_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __udivei4(res, lhs, rhs, bits); - return; - } - - zig_trap(); -} - -static inline void zig_div_floor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_div_trunc_big(res, lhs, rhs, is_signed, bits); - return; - } - - zig_trap(); -} - -zig_extern void __umodei4(uint32_t *res, const uint32_t *lhs, const uint32_t *rhs, uintptr_t bits); -static inline void zig_rem_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - __umodei4(res, lhs, rhs, bits); - return; - } - - zig_trap(); -} - -static inline void zig_mod_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { - if (!is_signed) { - zig_rem_big(res, lhs, rhs, is_signed, bits); - return; - } - - zig_trap(); -} - -static inline uint16_t zig_clz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t skip_bits = remaining_bytes * 8 - bits; - uint16_t total_lz = 0; - uint16_t limb_lz; - (void)is_signed; - -#if zig_little_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - { - zig_u128 val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u128(val_limb, 128 - skip_bits); - } - - total_lz += limb_lz; - if (limb_lz < 128 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u64(val_limb, 64 - skip_bits); - } - - total_lz += limb_lz; - if (limb_lz < 64 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u32(val_limb, 32 - skip_bits); - } - - total_lz += limb_lz; - if (limb_lz < 32 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - { - uint16_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u16(val_limb, 16 - skip_bits); - } - - total_lz += limb_lz; - if (limb_lz < 16 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { -#if zig_little_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - { - uint8_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_lz = zig_clz_u8(val_limb, 8 - skip_bits); - } - - total_lz += limb_lz; - if (limb_lz < 8 - skip_bits) return total_lz; - skip_bits = 0; - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_big_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return total_lz; -} - -static inline uint16_t zig_ctz_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_tz = 0; - uint16_t limb_tz; - (void)is_signed; - -#if zig_big_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - { - zig_u128 val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u128(val_limb, 128); - } - - total_tz += limb_tz; - if (limb_tz < 128) return total_tz; - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u64(val_limb, 64); - } - - total_tz += limb_tz; - if (limb_tz < 64) return total_tz; - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u32(val_limb, 32); - } - - total_tz += limb_tz; - if (limb_tz < 32) return total_tz; - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - { - uint16_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u16(val_limb, 16); - } - - total_tz += limb_tz; - if (limb_tz < 16) return total_tz; - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - { - uint8_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - limb_tz = zig_ctz_u8(val_limb, 8); - } - - total_tz += limb_tz; - if (limb_tz < 8) return total_tz; - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return total_tz; -} - -static inline uint16_t zig_popcount_big(const void *val, bool is_signed, uint16_t bits) { - const uint8_t *val_bytes = val; - uint16_t byte_offset = 0; - uint16_t remaining_bytes = zig_int_bytes(bits); - uint16_t total_pc = 0; - (void)is_signed; - -#if zig_big_endian - byte_offset = remaining_bytes; -#endif - - while (remaining_bytes >= 128 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 128 / CHAR_BIT; -#endif - - { - zig_u128 val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u128(val_limb, 128); - } - - remaining_bytes -= 128 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 128 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 64 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 64 / CHAR_BIT; -#endif - - { - uint64_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u64(val_limb, 64); - } - - remaining_bytes -= 64 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 64 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 32 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 32 / CHAR_BIT; -#endif - - { - uint32_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc += zig_popcount_u32(val_limb, 32); - } - - remaining_bytes -= 32 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 32 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 16 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 16 / CHAR_BIT; -#endif - - { - uint16_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u16(val_limb, 16); - } - - remaining_bytes -= 16 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 16 / CHAR_BIT; -#endif - } - - while (remaining_bytes >= 8 / CHAR_BIT) { -#if zig_big_endian - byte_offset -= 8 / CHAR_BIT; -#endif - - { - uint8_t val_limb; - - memcpy(&val_limb, &val_bytes[byte_offset], sizeof(val_limb)); - total_pc = zig_popcount_u8(val_limb, 8); - } - - remaining_bytes -= 8 / CHAR_BIT; - -#if zig_little_endian - byte_offset += 8 / CHAR_BIT; -#endif - } - - return total_pc; -} - -/* ========================= Floating Point Support ========================= */ - -#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ -#define __STDC_WANT_IEC_60559_TYPES_EXT__ -#endif - -#include - -#if defined(zig_msvc) -float __cdecl nanf(char const* input); -double __cdecl nan(char const* input); -long double __cdecl nanl(char const* input); - -#define zig_msvc_flt_inf ((double)(1e+300 * 1e+300)) -#define zig_msvc_flt_inff ((float)(1e+300 * 1e+300)) -#define zig_msvc_flt_infl ((long double)(1e+300 * 1e+300)) -#define zig_msvc_flt_nan ((double)(zig_msvc_flt_inf * 0.f)) -#define zig_msvc_flt_nanf ((float)(zig_msvc_flt_inf * 0.f)) -#define zig_msvc_flt_nanl ((long double)(zig_msvc_flt_inf * 0.f)) -#define __builtin_nan(str) nan(str) -#define __builtin_nanf(str) nanf(str) -#define __builtin_nanl(str) nanl(str) -#define __builtin_inf() zig_msvc_flt_inf -#define __builtin_inff() zig_msvc_flt_inff -#define __builtin_infl() zig_msvc_flt_infl -#endif - -#if (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) || defined(zig_gcc) -#define zig_make_special_f16(sign, name, arg, repr) sign zig_make_f16 (__builtin_##name, )(arg) -#define zig_make_special_f32(sign, name, arg, repr) sign zig_make_f32 (__builtin_##name, )(arg) -#define zig_make_special_f64(sign, name, arg, repr) sign zig_make_f64 (__builtin_##name, )(arg) -#define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg) -#define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) -#else -#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr) -#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr) -#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr) -#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr) -#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr) -#endif - -#define zig_has_f16 1 -#define zig_libc_name_f16(name) __##name##h -#define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) -#if FLT_MANT_DIG == 11 -typedef float zig_f16; -#define zig_make_f16(fp, repr) fp##f -#elif DBL_MANT_DIG == 11 -typedef double zig_f16; -#define zig_make_f16(fp, repr) fp -#elif LDBL_MANT_DIG == 11 -typedef long double zig_f16; -#define zig_make_f16(fp, repr) fp##l -#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gcc)) -typedef _Float16 zig_f16; -#define zig_make_f16(fp, repr) fp##f16 -#elif defined(__SIZEOF_FP16__) -typedef __fp16 zig_f16; -#define zig_make_f16(fp, repr) fp##f16 -#else -#undef zig_has_f16 -#define zig_has_f16 0 -#define zig_repr_f16 u16 -typedef uint16_t zig_f16; -#define zig_make_f16(fp, repr) repr -#undef zig_make_special_f16 -#define zig_make_special_f16(sign, name, arg, repr) repr -#undef zig_init_special_f16 -#define zig_init_special_f16(sign, name, arg, repr) repr -#endif -#if defined(zig_darwin) && defined(zig_x86) -typedef uint16_t zig_compiler_rt_f16; -#else -typedef zig_f16 zig_compiler_rt_f16; -#endif - -#define zig_has_f32 1 -#define zig_libc_name_f32(name) name##f -#if defined(zig_msvc) -#define zig_init_special_f32(sign, name, arg, repr) sign zig_make_f32(zig_msvc_flt_##name, ) -#else -#define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) -#endif -#if FLT_MANT_DIG == 24 -typedef float zig_f32; -#define zig_make_f32(fp, repr) fp##f -#elif DBL_MANT_DIG == 24 -typedef double zig_f32; -#define zig_make_f32(fp, repr) fp -#elif LDBL_MANT_DIG == 24 -typedef long double zig_f32; -#define zig_make_f32(fp, repr) fp##l -#elif FLT32_MANT_DIG == 24 -typedef _Float32 zig_f32; -#define zig_make_f32(fp, repr) fp##f32 -#else -#undef zig_has_f32 -#define zig_has_f32 0 -#define zig_repr_f32 u32 -typedef uint32_t zig_f32; -#define zig_make_f32(fp, repr) repr -#undef zig_make_special_f32 -#define zig_make_special_f32(sign, name, arg, repr) repr -#undef zig_init_special_f32 -#define zig_init_special_f32(sign, name, arg, repr) repr -#endif - -#define zig_has_f64 1 -#define zig_libc_name_f64(name) name - -#if defined(zig_msvc) -#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) -#else -#define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) -#endif -#if FLT_MANT_DIG == 53 -typedef float zig_f64; -#define zig_make_f64(fp, repr) fp##f -#elif DBL_MANT_DIG == 53 -typedef double zig_f64; -#define zig_make_f64(fp, repr) fp -#elif LDBL_MANT_DIG == 53 -typedef long double zig_f64; -#define zig_make_f64(fp, repr) fp##l -#elif FLT64_MANT_DIG == 53 -typedef _Float64 zig_f64; -#define zig_make_f64(fp, repr) fp##f64 -#elif FLT32X_MANT_DIG == 53 -typedef _Float32x zig_f64; -#define zig_make_f64(fp, repr) fp##f32x -#else -#undef zig_has_f64 -#define zig_has_f64 0 -#define zig_repr_f64 u64 -typedef uint64_t zig_f64; -#define zig_make_f64(fp, repr) repr -#undef zig_make_special_f64 -#define zig_make_special_f64(sign, name, arg, repr) repr -#undef zig_init_special_f64 -#define zig_init_special_f64(sign, name, arg, repr) repr -#endif - -#define zig_has_f80 1 -#define zig_libc_name_f80(name) __##name##x -#define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) -#if FLT_MANT_DIG == 64 -typedef float zig_f80; -#define zig_make_f80(fp, repr) fp##f -#elif DBL_MANT_DIG == 64 -typedef double zig_f80; -#define zig_make_f80(fp, repr) fp -#elif LDBL_MANT_DIG == 64 -typedef long double zig_f80; -#define zig_make_f80(fp, repr) fp##l -#elif FLT80_MANT_DIG == 64 -typedef _Float80 zig_f80; -#define zig_make_f80(fp, repr) fp##f80 -#elif FLT64X_MANT_DIG == 64 -typedef _Float64x zig_f80; -#define zig_make_f80(fp, repr) fp##f64x -#elif defined(__SIZEOF_FLOAT80__) -typedef __float80 zig_f80; -#define zig_make_f80(fp, repr) fp##l -#else -#undef zig_has_f80 -#define zig_has_f80 0 -#define zig_repr_f80 u128 -typedef zig_u128 zig_f80; -#define zig_make_f80(fp, repr) repr -#undef zig_make_special_f80 -#define zig_make_special_f80(sign, name, arg, repr) repr -#undef zig_init_special_f80 -#define zig_init_special_f80(sign, name, arg, repr) repr -#endif - -#if defined(zig_gcc) && defined(zig_x86) -#define zig_f128_has_miscompilations 1 -#else -#define zig_f128_has_miscompilations 0 -#endif - -#define zig_has_f128 1 -#define zig_libc_name_f128(name) name##q -#define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) -#if !zig_f128_has_miscompilations && FLT_MANT_DIG == 113 -typedef float zig_f128; -#define zig_make_f128(fp, repr) fp##f -#elif !zig_f128_has_miscompilations && DBL_MANT_DIG == 113 -typedef double zig_f128; -#define zig_make_f128(fp, repr) fp -#elif !zig_f128_has_miscompilations && LDBL_MANT_DIG == 113 -typedef long double zig_f128; -#define zig_make_f128(fp, repr) fp##l -#elif !zig_f128_has_miscompilations && FLT128_MANT_DIG == 113 -typedef _Float128 zig_f128; -#define zig_make_f128(fp, repr) fp##f128 -#elif !zig_f128_has_miscompilations && FLT64X_MANT_DIG == 113 -typedef _Float64x zig_f128; -#define zig_make_f128(fp, repr) fp##f64x -#elif !zig_f128_has_miscompilations && defined(__SIZEOF_FLOAT128__) -typedef __float128 zig_f128; -#define zig_make_f128(fp, repr) fp##q -#undef zig_make_special_f128 -#define zig_make_special_f128(sign, name, arg, repr) sign __builtin_##name##f128(arg) -#else -#undef zig_has_f128 -#define zig_has_f128 0 -#undef zig_make_special_f128 -#undef zig_init_special_f128 -#if defined(zig_darwin) || defined(zig_aarch64) -typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64; -zig_basic_operator(zig_v2u64, xor_v2u64, ^) -#define zig_repr_f128 v2u64 -typedef zig_v2u64 zig_f128; -#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi } -#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128 -#define zig_make_f128(fp, repr) zig_make_f128_##repr -#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr -#else -#define zig_repr_f128 u128 -typedef zig_u128 zig_f128; -#define zig_make_f128(fp, repr) repr -#define zig_make_special_f128(sign, name, arg, repr) repr -#define zig_init_special_f128(sign, name, arg, repr) repr -#endif -#endif - -#if !defined(zig_msvc) && defined(ZIG_TARGET_ABI_MSVC) -/* Emulate msvc abi on a gnu compiler */ -typedef zig_f64 zig_c_longdouble; -#elif defined(zig_msvc) && !defined(ZIG_TARGET_ABI_MSVC) -/* Emulate gnu abi on an msvc compiler */ -typedef zig_f128 zig_c_longdouble; -#else -/* Target and compiler abi match */ -typedef long double zig_c_longdouble; -#endif - -#define zig_bitCast_float(Type, ReprType) \ - static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \ - zig_##Type result; \ - memcpy(&result, &repr, sizeof(result)); \ - return result; \ - } -zig_bitCast_float(f16, uint16_t) -zig_bitCast_float(f32, uint32_t) -zig_bitCast_float(f64, uint64_t) -zig_bitCast_float(f80, zig_u128) -zig_bitCast_float(f128, zig_u128) - -#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \ - zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \ - static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \ - ResType res; \ - ExternResType extern_res; \ - ExternArgType extern_arg; \ - memcpy(&extern_arg, &arg, sizeof(extern_arg)); \ - extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \ - memcpy(&res, &extern_res, sizeof(res)); \ - return extern_res; \ - } -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2) -zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_d2f(zig_f64); -static inline zig_f32 zig_truncdfsf(zig_f64 arg) { return __aeabi_d2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_f2d(zig_f32); -static inline zig_f64 zig_extendsfdf(zig_f32 arg) { return __aeabi_f2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2) -zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2) - -#endif /* __ARM_EABI__ */ - -#define zig_float_negate_builtin_0(w, c, sb) \ - zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb)) -#define zig_float_negate_builtin_1(w, c, sb) -arg -#define zig_float_negate_builtin(w, c, sb) \ - static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \ - return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \ - } -zig_float_negate_builtin(16, , UINT16_C(1) << 15 ) -zig_float_negate_builtin(32, , UINT32_C(1) << 31 ) -zig_float_negate_builtin(64, , UINT64_C(1) << 63 ) -zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0))) -zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) - -#define zig_float_less_builtin_0(Type, operation) \ - zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_zig_##Type), 2)(zig_##Type, zig_##Type); \ - static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 2)(lhs, rhs); \ - } -#define zig_float_less_builtin_1(Type, operation) \ - static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return (!(lhs <= rhs) - (lhs < rhs)); \ - } - -#define zig_float_greater_builtin_0(Type, operation) \ - zig_float_less_builtin_0(Type, operation) -#define zig_float_greater_builtin_1(Type, operation) \ - static inline int32_t zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return ((lhs > rhs) - !(lhs >= rhs)); \ - } - -#define zig_float_binary_builtin_0(Type, operation, operator) \ - zig_extern zig_##Type zig_expand_concat(zig_expand_concat(__##operation, \ - zig_compiler_rt_abbrev_zig_##Type), 3)(zig_##Type, zig_##Type); \ - static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return zig_expand_concat(zig_expand_concat(__##operation, zig_compiler_rt_abbrev_zig_##Type), 3)(lhs, rhs); \ - } -#define zig_float_binary_builtin_1(Type, operation, operator) \ - static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ - return lhs operator rhs; \ - } - -#define zig_common_float_builtins(w) \ - zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \ - zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \ - zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \ - zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \ - zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, lt) \ - zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, le) \ - zig_expand_concat(zig_float_greater_builtin_, zig_has_f##w)(f##w, gt) \ - zig_expand_concat(zig_float_greater_builtin_, zig_has_f##w)(f##w, ge) \ - zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, add, +) \ - zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \ - zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \ - zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sqrt)))(zig_f##w, zig_sqrt_f##w, zig_libc_name_f##w(sqrt), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sin)))(zig_f##w, zig_sin_f##w, zig_libc_name_f##w(sin), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(cos)))(zig_f##w, zig_cos_f##w, zig_libc_name_f##w(cos), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(tan)))(zig_f##w, zig_tan_f##w, zig_libc_name_f##w(tan), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp)))(zig_f##w, zig_exp_f##w, zig_libc_name_f##w(exp), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp2)))(zig_f##w, zig_exp2_f##w, zig_libc_name_f##w(exp2), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log)))(zig_f##w, zig_log_f##w, zig_libc_name_f##w(log), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log2)))(zig_f##w, zig_log2_f##w, zig_libc_name_f##w(log2), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log10)))(zig_f##w, zig_log10_f##w, zig_libc_name_f##w(log10), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fabs)))(zig_f##w, zig_abs_f##w, zig_libc_name_f##w(fabs), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(floor)))(zig_f##w, zig_floor_f##w, zig_libc_name_f##w(floor), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(ceil)))(zig_f##w, zig_ceil_f##w, zig_libc_name_f##w(ceil), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(round)))(zig_f##w, zig_round_f##w, zig_libc_name_f##w(round), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(trunc)))(zig_f##w, zig_trunc_f##w, zig_libc_name_f##w(trunc), (zig_f##w x), (x)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmod)))(zig_f##w, zig_fmod_f##w, zig_libc_name_f##w(fmod), (zig_f##w x, zig_f##w y), (x, y)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmin)))(zig_f##w, zig_min_f##w, zig_libc_name_f##w(fmin), (zig_f##w x, zig_f##w y), (x, y)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_max_f##w, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ - zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_fma_f##w, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ -\ - static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_trunc_f##w(zig_div_f##w(lhs, rhs)); \ - } \ -\ - static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_floor_f##w(zig_div_f##w(lhs, rhs)); \ - } \ -\ - static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ - return zig_sub_f##w(lhs, zig_mul_f##w(zig_div_floor_f##w(lhs, rhs), rhs)); \ - } -zig_common_float_builtins(16) -zig_common_float_builtins(32) -zig_common_float_builtins(64) -zig_common_float_builtins(80) -zig_common_float_builtins(128) - -#define zig_float_builtins(w) \ - zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \ - zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) -zig_float_builtins(16) -zig_float_builtins(80) -zig_float_builtins(128) - -#ifdef __ARM_EABI__ - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_f2iz(zig_f32); -static inline int32_t zig_fixsfsi(zig_f32 arg) { return __aeabi_f2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_f2uiz(zig_f32); -static inline uint32_t zig_fixunssfsi(zig_f32 arg) { return __aeabi_f2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_f2ulz(zig_f32); -static inline uint64_t zig_fixunssfdi(zig_f32 arg) { return __aeabi_f2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_i2f(int32_t); -static inline zig_f32 zig_floatsisf(int32_t arg) { return __aeabi_i2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ui2f(uint32_t); -static inline zig_f32 zig_floatunsisf(uint32_t arg) { return __aeabi_ui2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f32 __aeabi_ul2f(uint64_t); -static inline zig_f32 zig_floatundisf(uint64_t arg) { return __aeabi_ul2f(arg); } - -zig_extern zig_callconv(pcs("aapcs")) int32_t __aeabi_d2iz(zig_f64); -static inline int32_t zig_fixdfsi(zig_f64 arg) { return __aeabi_d2iz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint32_t __aeabi_d2uiz(zig_f64); -static inline uint32_t zig_fixunsdfsi(zig_f64 arg) { return __aeabi_d2uiz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) uint64_t __aeabi_d2ulz(zig_f64); -static inline uint64_t zig_fixunsdfdi(zig_f64 arg) { return __aeabi_d2ulz(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_i2d(int32_t); -static inline zig_f64 zig_floatsidf(int32_t arg) { return __aeabi_i2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ui2d(uint32_t); -static inline zig_f64 zig_floatunsidf(uint32_t arg) { return __aeabi_ui2d(arg); } - -zig_extern zig_callconv(pcs("aapcs")) zig_f64 __aeabi_ul2d(uint64_t); -static inline zig_f64 zig_floatundidf(uint64_t arg) { return __aeabi_ul2d(arg); } - -#else /* __ARM_EABI__ */ - -zig_float_builtins(32) -zig_float_builtins(64) - -#endif /* __ARM_EABI__ */ - -/* ============================ Atomics Support ============================= */ - -/* Note that atomics should be implemented as macros because most - compilers silently discard runtime atomic order information. */ - -/* Define fallback implementations first that can later be undef'd on compilers with builtin support. */ -/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */ -#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) - -#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) -#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \ - zig_##Type zig_atomicrmw_expected; \ - zig_##Type zig_atomicrmw_desired; \ - zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ - do { \ - zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \ - } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ - res = zig_atomicrmw_expected; \ -} while (0) - -#if (__STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)) || (zig_has_include() && !defined(zig_msvc)) -#define zig_c11_atomics -#endif - -#if defined(zig_c11_atomics) -#include -typedef enum memory_order zig_memory_order; -#define zig_memory_order_relaxed memory_order_relaxed -#define zig_memory_order_acquire memory_order_acquire -#define zig_memory_order_release memory_order_release -#define zig_memory_order_acq_rel memory_order_acq_rel -#define zig_memory_order_seq_cst memory_order_seq_cst -#define zig_atomic(Type) _Atomic(Type) -#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) -#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) -#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = atomic_exchange_explicit (obj, arg, order) -#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = atomic_fetch_add_explicit (obj, arg, order) -#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = atomic_fetch_sub_explicit (obj, arg, order) -#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = atomic_fetch_or_explicit (obj, arg, order) -#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = atomic_fetch_xor_explicit (obj, arg, order) -#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = atomic_fetch_and_explicit (obj, arg, order) -#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order) -#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order) -#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order) -#define zig_atomic_store( obj, arg, order, Type, ReprType) atomic_store_explicit (obj, arg, order) -#define zig_atomic_load(res, obj, order, Type, ReprType) res = atomic_load_explicit (obj, order) -#undef zig_atomicrmw_xchg_float -#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg -#undef zig_atomicrmw_add_float -#define zig_atomicrmw_add_float zig_atomicrmw_add -#undef zig_atomicrmw_sub_float -#define zig_atomicrmw_sub_float zig_atomicrmw_sub -#elif defined(zig_gnuc) -typedef int zig_memory_order; -#define zig_memory_order_relaxed __ATOMIC_RELAXED -#define zig_memory_order_acquire __ATOMIC_ACQUIRE -#define zig_memory_order_release __ATOMIC_RELEASE -#define zig_memory_order_acq_rel __ATOMIC_ACQ_REL -#define zig_memory_order_seq_cst __ATOMIC_SEQ_CST -#define zig_atomic(Type) Type -#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, (ReprType *)&(expected), (ReprType *)&(desired), false, succ, fail) -#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, (ReprType *)&(expected), (ReprType *)&(desired), true, succ, fail) -#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) __atomic_exchange(obj, (ReprType *)&(arg), &(res), order) -#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_add (obj, arg, order) -#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_sub (obj, arg, order) -#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_or (obj, arg, order) -#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_xor (obj, arg, order) -#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_and (obj, arg, order) -#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order) -#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order) -#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order) -#define zig_atomic_store( obj, arg, order, Type, ReprType) __atomic_store (obj, (ReprType *)&(arg), order) -#define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order) -#undef zig_atomicrmw_xchg_float -#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg -#elif defined(zig_msvc) && defined(zig_x86) -#define zig_memory_order_relaxed 0 -#define zig_memory_order_acquire 2 -#define zig_memory_order_release 3 -#define zig_memory_order_acq_rel 4 -#define zig_memory_order_seq_cst 5 -#define zig_atomic(Type) Type -#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired) -#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType) -#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xchg_##Type(obj, arg) -#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_add_ ##Type(obj, arg) -#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_sub_ ##Type(obj, arg) -#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_or_ ##Type(obj, arg) -#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xor_ ##Type(obj, arg) -#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_and_ ##Type(obj, arg) -#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_nand_##Type(obj, arg) -#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_min_ ##Type(obj, arg) -#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg) -#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg) -#define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##order##_##Type(obj) -/* TODO: zig_msvc && (zig_thumb || zig_aarch64) */ -#else -#define zig_memory_order_relaxed 0 -#define zig_memory_order_acquire 2 -#define zig_memory_order_release 3 -#define zig_memory_order_acq_rel 4 -#define zig_memory_order_seq_cst 5 -#define zig_atomic(Type) Type -#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable -#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable -#define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable -#endif - -#if !defined(zig_c11_atomics) && defined(zig_msvc) && defined(zig_x86) - -/* TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 */ - -#define zig_msvc_atomics(ZigType, Type, SigType, suffix, iso_suffix) \ - static inline bool zig_msvc_cmpxchg_##ZigType(Type volatile* obj, Type* expected, Type desired) { \ - Type comparand = *expected; \ - Type initial = _InterlockedCompareExchange##suffix((SigType volatile*)obj, (SigType)desired, (SigType)comparand); \ - bool exchanged = initial == comparand; \ - if (!exchanged) { \ - *expected = initial; \ - } \ - return exchanged; \ - } \ - static inline Type zig_msvc_atomicrmw_xchg_##ZigType(Type volatile* obj, Type value) { \ - return _InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomicrmw_add_##ZigType(Type volatile* obj, Type value) { \ - return _InterlockedExchangeAdd##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomicrmw_sub_##ZigType(Type volatile* obj, Type value) { \ - bool success = false; \ - Type new; \ - Type prev; \ - while (!success) { \ - prev = *obj; \ - new = prev - value; \ - success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ - } \ - return prev; \ - } \ - static inline Type zig_msvc_atomicrmw_or_##ZigType(Type volatile* obj, Type value) { \ - return _InterlockedOr##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomicrmw_xor_##ZigType(Type volatile* obj, Type value) { \ - return _InterlockedXor##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomicrmw_and_##ZigType(Type volatile* obj, Type value) { \ - return _InterlockedAnd##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomicrmw_nand_##ZigType(Type volatile* obj, Type value) { \ - bool success = false; \ - Type new; \ - Type prev; \ - while (!success) { \ - prev = *obj; \ - new = ~(prev & value); \ - success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ - } \ - return prev; \ - } \ - static inline Type zig_msvc_atomicrmw_min_##ZigType(Type volatile* obj, Type value) { \ - bool success = false; \ - Type new; \ - Type prev; \ - while (!success) { \ - prev = *obj; \ - new = value < prev ? value : prev; \ - success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ - } \ - return prev; \ - } \ - static inline Type zig_msvc_atomicrmw_max_##ZigType(Type volatile* obj, Type value) { \ - bool success = false; \ - Type new; \ - Type prev; \ - while (!success) { \ - prev = *obj; \ - new = value > prev ? value : prev; \ - success = zig_msvc_cmpxchg_##ZigType(obj, &prev, new); \ - } \ - return prev; \ - } \ - static inline void zig_msvc_atomic_store_##ZigType(Type volatile* obj, Type value) { \ - (void)_InterlockedExchange##suffix((SigType volatile*)obj, (SigType)value); \ - } \ - static inline Type zig_msvc_atomic_load_zig_memory_order_relaxed_##ZigType(Type volatile* obj) { \ - return __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - } \ - static inline Type zig_msvc_atomic_load_zig_memory_order_acquire_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - _ReadWriteBarrier(); \ - return val; \ - } \ - static inline Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##ZigType(Type volatile* obj) { \ - Type val = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - _ReadWriteBarrier(); \ - return val; \ - } - -zig_msvc_atomics( u8, uint8_t, char, 8, 8) -zig_msvc_atomics( i8, int8_t, char, 8, 8) -zig_msvc_atomics(u16, uint16_t, short, 16, 16) -zig_msvc_atomics(i16, int16_t, short, 16, 16) -zig_msvc_atomics(u32, uint32_t, long, , 32) -zig_msvc_atomics(i32, int32_t, long, , 32) - -#if defined(zig_x86_64) -zig_msvc_atomics(u64, uint64_t, __int64, 64, 64) -zig_msvc_atomics(i64, int64_t, __int64, 64, 64) -#endif - -#define zig_msvc_flt_atomics(Type, SigType, suffix, iso_suffix) \ - static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \ - SigType exchange; \ - SigType comparand; \ - SigType initial; \ - bool success; \ - memcpy(&comparand, expected, sizeof(comparand)); \ - memcpy(&exchange, &desired, sizeof(exchange)); \ - initial = _InterlockedCompareExchange##suffix((SigType volatile*)obj, exchange, comparand); \ - success = initial == comparand; \ - if (!success) memcpy(expected, &initial, sizeof(*expected)); \ - return success; \ - } \ - static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type arg) { \ - SigType value; \ - memcpy(&value, &arg, sizeof(value)); \ - (void)_InterlockedExchange##suffix((SigType volatile*)obj, value); \ - } \ - static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_relaxed_##Type(zig_##Type volatile* obj) { \ - zig_##Type result; \ - SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - memcpy(&result, &initial, sizeof(result)); \ - return result; \ - } \ - static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_acquire_##Type(zig_##Type volatile* obj) { \ - zig_##Type result; \ - SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ - return result; \ - } \ - static inline zig_##Type zig_msvc_atomic_load_zig_memory_order_seq_cst_##Type(zig_##Type volatile* obj) { \ - zig_##Type result; \ - SigType initial = __iso_volatile_load##iso_suffix((SigType volatile*)obj); \ - _ReadWriteBarrier(); \ - memcpy(&result, &initial, sizeof(result)); \ - return result; \ - } - -zig_msvc_flt_atomics(f32, long, , 32) -#if defined(zig_x86_64) -zig_msvc_flt_atomics(f64, int64_t, 64, 64) -#endif - -#if defined(zig_x86_32) -static inline void zig_msvc_atomic_barrier() { - int32_t barrier; - __asm { - xchg barrier, eax - } -} - -static inline void* zig_msvc_atomicrmw_xchg_p32(void volatile* obj, void* arg) { - return _InterlockedExchangePointer(obj, arg); -} - -static inline void zig_msvc_atomic_store_p32(void volatile* obj, void* arg) { - (void)_InterlockedExchangePointer(obj, arg); -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p32(void volatile* obj) { - return (void*)__iso_volatile_load32(obj); -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p32(void volatile* obj) { - void* val = (void*)__iso_volatile_load32(obj); - _ReadWriteBarrier(); - return val; -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p32(void volatile* obj) { - return zig_msvc_atomic_load_zig_memory_order_acquire_p32(obj); -} - -static inline bool zig_msvc_cmpxchg_p32(void volatile* obj, void* expected, void* desired) { - void* comparand = *(void**)expected; - void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand); - bool success = initial == comparand; - if (!success) *(void**)expected = initial; - return success; -} -#else /* zig_x86_32 */ -static inline void* zig_msvc_atomicrmw_xchg_p64(void volatile* obj, void* arg) { - return _InterlockedExchangePointer(obj, arg); -} - -static inline void zig_msvc_atomic_store_p64(void volatile* obj, void* arg) { - (void)_InterlockedExchangePointer(obj, arg); -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_relaxed_p64(void volatile* obj) { - return (void*)__iso_volatile_load64(obj); -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_acquire_p64(void volatile* obj) { - void* val = (void*)__iso_volatile_load64(obj); - _ReadWriteBarrier(); - return val; -} - -static inline void* zig_msvc_atomic_load_zig_memory_order_seq_cst_p64(void volatile* obj) { - return zig_msvc_atomic_load_zig_memory_order_acquire_p64(obj); -} - -static inline bool zig_msvc_cmpxchg_p64(void volatile* obj, void* expected, void* desired) { - void* comparand = *(void**)expected; - void* initial = _InterlockedCompareExchangePointer(obj, desired, comparand); - bool success = initial == comparand; - if (!success) *(void**)expected = initial; - return success; -} - -static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expected, zig_u128 desired) { - return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected); -} - -static inline zig_u128 zig_msvc_atomic_load_u128(zig_u128 volatile* obj) { - zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0)); - (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128); - return expected; -} - -static inline void zig_msvc_atomic_store_u128(zig_u128 volatile* obj, zig_u128 arg) { - zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0)); - while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128)); -} - -static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { - return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected); -} - -static inline zig_i128 zig_msvc_atomic_load_i128(zig_i128 volatile* obj) { - zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0)); - (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128); - return expected; -} - -static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 arg) { - zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0)); - while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128)); -} - -#endif /* zig_x86_32 */ - -#endif /* !zig_c11_atomics && zig_msvc && zig_x86 */ - -/* ======================== Special Case Intrinsics ========================= */ - -#if defined(zig_msvc) -#include -#endif - -#if defined(zig_thumb) - -static inline void* zig_thumb_windows_teb(void) { - void* teb = 0; -#if defined(zig_msvc) - teb = (void*)_MoveFromCoprocessor(15, 0, 13, 0, 2); -#elif defined(zig_gnuc_asm) - __asm__ ("mrc p15, 0, %[ptr], c13, c0, 2" : [ptr] "=r" (teb)); -#endif - return teb; -} - -#elif defined(zig_aarch64) - -static inline void* zig_aarch64_windows_teb(void) { - void* teb = 0; -#if defined(zig_msvc) - teb = (void*)__readx18qword(0x0); -#elif defined(zig_gnuc_asm) - __asm__ ("mov %[ptr], x18" : [ptr] "=r" (teb)); -#endif - return teb; -} - -#elif defined(zig_x86_32) - -static inline void* zig_x86_windows_teb(void) { - void* teb = 0; -#if defined(zig_msvc) - teb = (void*)__readfsdword(0x18); -#elif defined(zig_gnuc_asm) - __asm__ ("movl %%fs:0x18, %[ptr]" : [ptr] "=r" (teb)); -#endif - return teb; -} - -#elif defined(zig_x86_64) - -static inline void* zig_x86_64_windows_teb(void) { - void* teb = 0; -#if defined(zig_msvc) - teb = (void*)__readgsqword(0x30); -#elif defined(zig_gnuc_asm) - __asm__ ("movq %%gs:0x30, %[ptr]" : [ptr] "=r" (teb)); -#endif - return teb; -} - -#endif - -#if defined(zig_x86) - -static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) { -#if defined(zig_msvc) - int cpu_info[4]; - __cpuidex(cpu_info, leaf_id, subid); - *eax = (uint32_t)cpu_info[0]; - *ebx = (uint32_t)cpu_info[1]; - *ecx = (uint32_t)cpu_info[2]; - *edx = (uint32_t)cpu_info[3]; -#elif defined(zig_gnuc_asm) - __asm__("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(leaf_id), "c"(subid)); -#else - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; -#endif -} - -static inline uint32_t zig_x86_get_xcr0(void) { -#if defined(zig_msvc) - return (uint32_t)_xgetbv(0); -#elif defined(zig_gnuc_asm) - uint32_t eax; - uint32_t edx; - __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); - return eax; -#else - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; -#endif -} - -#endif diff --git a/testing/capi/vendor.sh b/testing/capi/vendor.sh deleted file mode 100755 index e1f900aa..00000000 --- a/testing/capi/vendor.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -INSTRUMENT_HOOKS_COMMIT="1752e9e4eae585e26703932d0055a1473dd77048" -INSTRUMENT_HOOKS_URL="https://github.com/CodSpeedHQ/instrument-hooks/archive/${INSTRUMENT_HOOKS_COMMIT}.tar.gz" -VENDOR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -TEMP_DIR=$(mktemp -d) - -rm -rf "${VENDOR_DIR}/instrument-hooks" - -# Download and extract the instrument-hooks library -curl -L "${INSTRUMENT_HOOKS_URL}" -o "${TEMP_DIR}/instrument-hooks.tar.gz" -tar -xzf "${TEMP_DIR}/instrument-hooks.tar.gz" -C "${TEMP_DIR}" - -# Copy only the dist and includes directories to the vendor directory -mkdir -p "${VENDOR_DIR}/instrument-hooks/" -cp -r "${TEMP_DIR}/instrument-hooks-${INSTRUMENT_HOOKS_COMMIT}/dist" "${VENDOR_DIR}/instrument-hooks/" -cp -r "${TEMP_DIR}/instrument-hooks-${INSTRUMENT_HOOKS_COMMIT}/includes" "${VENDOR_DIR}/instrument-hooks/" - -# Clean up -rm -rf "${TEMP_DIR}" diff --git a/testing/fork.sh b/testing/fork.sh deleted file mode 100755 index b545e7c1..00000000 --- a/testing/fork.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env bash -set -e # Exit on error - -# Ensure we're running from the testing/ directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$SCRIPT_DIR" - -GO_VERSION="${1:-1.25}" # Allow version override: ./fork.sh 1.25 - -# Copy internal packages from Go source to local internal/ directory -# Takes package names as arguments (e.g., "cpu" "fuzz" "race") -copy_internal_packages() { - for pkg in "$@"; do - mkdir -p "internal/$pkg" - cp -r "go/src/internal/$pkg"/* "internal/$pkg/" - done -} - -# Backup files to the hardcoded backup directory (.codspeed-backup) -# Usage: backup_files [file_or_dir ...] -backup_files() { - local backup_dir=".codspeed-backup" - mkdir -p "$backup_dir" - - for file in "$@"; do - if [ -e "$file" ]; then - cp -r "$file" "$backup_dir/$(basename "$file")" - echo "Backed up: $file" - fi - done -} - -# Restore files from the hardcoded backup directory (.codspeed-backup) -# Usage: restore_files [file_or_dir ...] -restore_files() { - local backup_dir=".codspeed-backup" - - echo "Restoring files from backup..." - for file in "$@"; do - local backup_file="$backup_dir/$(basename "$file")" - if [ -e "$backup_file" ]; then - # Remove destination first to avoid creating nested directories - rm -rf "$file" - mv "$backup_file" "$file" - echo "Restored: $file" - fi - done -} - -# Apply a patch file with error handling -# Usage: apply_patch [fuzz_factor] [working_directory] -# If working_directory is provided, patch is applied from there -apply_patch() { - local patch_file="$1" - local fuzz="${2:-2}" # Default fuzz factor is 2 - local workdir="${3:-.}" - - # Convert patch_file to absolute path if it's relative - if [[ "$patch_file" != /* ]]; then - patch_file="$SCRIPT_DIR/$patch_file" - fi - - if [ ! -f "$patch_file" ]; then - echo "ERROR: Patch file not found: $patch_file" - return 1 - fi - - echo "Applying patch: $(basename "$patch_file")..." - - if [ "$workdir" != "." ]; then - (cd "$workdir" && patch -p1 --forward --fuzz="$fuzz" < "$patch_file") || { - echo "ERROR: $patch_file failed to apply cleanly" - return 1 - } - else - patch -p1 --forward --fuzz="$fuzz" < "$patch_file" || { - echo "ERROR: $patch_file failed to apply cleanly" - return 1 - } - fi - echo "Successfully applied: $(basename "$patch_file")" -} - - -echo "Forking Go testing package from version ${GO_VERSION}..." - -# CodSpeed-specific files to preserve during fork -CODSPEED_FILES=( - "testing/codspeed.go" - "testing/fstest/testfs_readlinkfs_compat.go" - "testing/fstest/testfs_readlinkfs.go" -) -backup_files "${CODSPEED_FILES[@]}" - -# We need to copy the testing/ package: -rm -rf go testing internal -git clone -b "go${GO_VERSION}" --depth 1 https://github.com/golang/go/ -cp -r go/src/testing testing/ - -# Copy all required internal packages. We need them to have a clean `go mod tidy` output. -copy_internal_packages "cpu" "fuzz" "goarch" "race" "sysinfo" "testlog" "testenv" "syscall/windows" "godebug" "synctest" "bisect" "godebugs" "cfg" "platform" "diff" "txtar" -rm -rf go - -# Replace all `"internal/*"` imports with 'github.com/CodSpeedHQ/codspeed-go/testing/internal/' -find . -type f -name "*.go" -exec sed -i 's|"internal/|"github.com/CodSpeedHQ/codspeed-go/testing/internal/|g' {} + - -# Apply the race package patch to remove abi dependency -apply_patch "patches/internal_race.patch" 0 - -# Apply CodSpeed modifications to testing package (split into separate files) -apply_patch "patches/benchmark.patch" 10 "testing" -apply_patch "patches/testing.patch" 10 "testing" -apply_patch "patches/synctest.patch" 10 - -# `testing/testfs` uses Go 1.25 features that we need to patch out for compatibility with older Go versions -apply_patch "patches/testfs.patch" 10 "testing" - -# Replace all `"testing"` imports with 'testing "github.com/CodSpeedHQ/codspeed-go/testing/testing"' (only for non-test files) -find . -type f -name "*.go" -not -name "*_test.go" -exec sed -i 's|"testing"|testing "github.com/CodSpeedHQ/codspeed-go/testing/testing"|g' {} + - -# Restore CodSpeed-specific files -restore_files "${CODSPEED_FILES[@]}" - -apply_patch "patches/benchmark_stopbenchmark_fail.patch" 10 ".." -apply_patch "patches/benchmark_stoptimer_mitigation.patch" 10 ".." -apply_patch "patches/benchmark_benchmarkers_bloop.patch" 10 ".." -apply_patch "patches/benchmark_savemeasurement_bug.patch" 10 ".." -apply_patch "patches/benchmark_remove_codspeed_folder.patch" 10 ".." - - -# Run pre-commit and format the code -go fmt ./... > /dev/null 2>&1 || true -pre-commit run --all-files > /dev/null 2>&1 || true diff --git a/testing/internal/bisect/bisect.go b/testing/internal/bisect/bisect.go deleted file mode 100644 index a79bb800..00000000 --- a/testing/internal/bisect/bisect.go +++ /dev/null @@ -1,778 +0,0 @@ -// Copyright 2023 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 bisect can be used by compilers and other programs -// to serve as a target for the bisect debugging tool. -// See [golang.org/x/tools/cmd/bisect] for details about using the tool. -// -// To be a bisect target, allowing bisect to help determine which of a set of independent -// changes provokes a failure, a program needs to: -// -// 1. Define a way to accept a change pattern on its command line or in its environment. -// The most common mechanism is a command-line flag. -// The pattern can be passed to [New] to create a [Matcher], the compiled form of a pattern. -// -// 2. Assign each change a unique ID. One possibility is to use a sequence number, -// but the most common mechanism is to hash some kind of identifying information -// like the file and line number where the change might be applied. -// [Hash] hashes its arguments to compute an ID. -// -// 3. Enable each change that the pattern says should be enabled. -// The [Matcher.ShouldEnable] method answers this question for a given change ID. -// -// 4. Print a report identifying each change that the pattern says should be printed. -// The [Matcher.ShouldPrint] method answers this question for a given change ID. -// The report consists of one more lines on standard error or standard output -// that contain a “match marker”. [Marker] returns the match marker for a given ID. -// When bisect reports a change as causing the failure, it identifies the change -// by printing the report lines with the match marker removed. -// -// # Example Usage -// -// A program starts by defining how it receives the pattern. In this example, we will assume a flag. -// The next step is to compile the pattern: -// -// m, err := bisect.New(patternFlag) -// if err != nil { -// log.Fatal(err) -// } -// -// Then, each time a potential change is considered, the program computes -// a change ID by hashing identifying information (source file and line, in this case) -// and then calls m.ShouldPrint and m.ShouldEnable to decide whether to -// print and enable the change, respectively. The two can return different values -// depending on whether bisect is trying to find a minimal set of changes to -// disable or to enable to provoke the failure. -// -// It is usually helpful to write a helper function that accepts the identifying information -// and then takes care of hashing, printing, and reporting whether the identified change -// should be enabled. For example, a helper for changes identified by a file and line number -// would be: -// -// func ShouldEnable(file string, line int) { -// h := bisect.Hash(file, line) -// if m.ShouldPrint(h) { -// fmt.Fprintf(os.Stderr, "%v %s:%d\n", bisect.Marker(h), file, line) -// } -// return m.ShouldEnable(h) -// } -// -// Finally, note that New returns a nil Matcher when there is no pattern, -// meaning that the target is not running under bisect at all, -// so all changes should be enabled and none should be printed. -// In that common case, the computation of the hash can be avoided entirely -// by checking for m == nil first: -// -// func ShouldEnable(file string, line int) bool { -// if m == nil { -// return true -// } -// h := bisect.Hash(file, line) -// if m.ShouldPrint(h) { -// fmt.Fprintf(os.Stderr, "%v %s:%d\n", bisect.Marker(h), file, line) -// } -// return m.ShouldEnable(h) -// } -// -// When the identifying information is expensive to format, this code can call -// [Matcher.MarkerOnly] to find out whether short report lines containing only the -// marker are permitted for a given run. (Bisect permits such lines when it is -// still exploring the space of possible changes and will not be showing the -// output to the user.) If so, the client can choose to print only the marker: -// -// func ShouldEnable(file string, line int) bool { -// if m == nil { -// return true -// } -// h := bisect.Hash(file, line) -// if m.ShouldPrint(h) { -// if m.MarkerOnly() { -// bisect.PrintMarker(os.Stderr, h) -// } else { -// fmt.Fprintf(os.Stderr, "%v %s:%d\n", bisect.Marker(h), file, line) -// } -// } -// return m.ShouldEnable(h) -// } -// -// This specific helper – deciding whether to enable a change identified by -// file and line number and printing about the change when necessary – is -// provided by the [Matcher.FileLine] method. -// -// Another common usage is deciding whether to make a change in a function -// based on the caller's stack, to identify the specific calling contexts that the -// change breaks. The [Matcher.Stack] method takes care of obtaining the stack, -// printing it when necessary, and reporting whether to enable the change -// based on that stack. -// -// # Pattern Syntax -// -// Patterns are generated by the bisect tool and interpreted by [New]. -// Users should not have to understand the patterns except when -// debugging a target's bisect support or debugging the bisect tool itself. -// -// The pattern syntax selecting a change is a sequence of bit strings -// separated by + and - operators. Each bit string denotes the set of -// changes with IDs ending in those bits, + is set addition, - is set subtraction, -// and the expression is evaluated in the usual left-to-right order. -// The special binary number “y” denotes the set of all changes, -// standing in for the empty bit string. -// In the expression, all the + operators must appear before all the - operators. -// A leading + adds to an empty set. A leading - subtracts from the set of all -// possible suffixes. -// -// For example: -// -// - “01+10” and “+01+10” both denote the set of changes -// with IDs ending with the bits 01 or 10. -// -// - “01+10-1001” denotes the set of changes with IDs -// ending with the bits 01 or 10, but excluding those ending in 1001. -// -// - “-01-1000” and “y-01-1000 both denote the set of all changes -// with IDs not ending in 01 nor 1000. -// -// - “0+1-01+001” is not a valid pattern, because all the + operators do not -// appear before all the - operators. -// -// In the syntaxes described so far, the pattern specifies the changes to -// enable and report. If a pattern is prefixed by a “!”, the meaning -// changes: the pattern specifies the changes to DISABLE and report. This -// mode of operation is needed when a program passes with all changes -// enabled but fails with no changes enabled. In this case, bisect -// searches for minimal sets of changes to disable. -// Put another way, the leading “!” inverts the result from [Matcher.ShouldEnable] -// but does not invert the result from [Matcher.ShouldPrint]. -// -// As a convenience for manual debugging, “n” is an alias for “!y”, -// meaning to disable and report all changes. -// -// Finally, a leading “v” in the pattern indicates that the reports will be shown -// to the user of bisect to describe the changes involved in a failure. -// At the API level, the leading “v” causes [Matcher.Visible] to return true. -// See the next section for details. -// -// # Match Reports -// -// The target program must enable only those changed matched -// by the pattern, and it must print a match report for each such change. -// A match report consists of one or more lines of text that will be -// printed by the bisect tool to describe a change implicated in causing -// a failure. Each line in the report for a given change must contain a -// match marker with that change ID, as returned by [Marker]. -// The markers are elided when displaying the lines to the user. -// -// A match marker has the form “[bisect-match 0x1234]” where -// 0x1234 is the change ID in hexadecimal. -// An alternate form is “[bisect-match 010101]”, giving the change ID in binary. -// -// When [Matcher.Visible] returns false, the match reports are only -// being processed by bisect to learn the set of enabled changes, -// not shown to the user, meaning that each report can be a match -// marker on a line by itself, eliding the usual textual description. -// When the textual description is expensive to compute, -// checking [Matcher.Visible] can help the avoid that expense -// in most runs. -package bisect - -import ( - "runtime" - "sync" - "sync/atomic" -) - -// New creates and returns a new Matcher implementing the given pattern. -// The pattern syntax is defined in the package doc comment. -// -// In addition to the pattern syntax syntax, New("") returns nil, nil. -// The nil *Matcher is valid for use: it returns true from ShouldEnable -// and false from ShouldPrint for all changes. Callers can avoid calling -// [Hash], [Matcher.ShouldEnable], and [Matcher.ShouldPrint] entirely -// when they recognize the nil Matcher. -func New(pattern string) (*Matcher, error) { - if pattern == "" { - return nil, nil - } - - m := new(Matcher) - - p := pattern - // Special case for leading 'q' so that 'qn' quietly disables, e.g. fmahash=qn to disable fma - // Any instance of 'v' disables 'q'. - if len(p) > 0 && p[0] == 'q' { - m.quiet = true - p = p[1:] - if p == "" { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - } - // Allow multiple v, so that “bisect cmd vPATTERN” can force verbose all the time. - for len(p) > 0 && p[0] == 'v' { - m.verbose = true - m.quiet = false - p = p[1:] - if p == "" { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - } - - // Allow multiple !, each negating the last, so that “bisect cmd !PATTERN” works - // even when bisect chooses to add its own !. - m.enable = true - for len(p) > 0 && p[0] == '!' { - m.enable = !m.enable - p = p[1:] - if p == "" { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - } - - if p == "n" { - // n is an alias for !y. - m.enable = !m.enable - p = "y" - } - - // Parse actual pattern syntax. - result := true - bits := uint64(0) - start := 0 - wid := 1 // 1-bit (binary); sometimes 4-bit (hex) - for i := 0; i <= len(p); i++ { - // Imagine a trailing - at the end of the pattern to flush final suffix - c := byte('-') - if i < len(p) { - c = p[i] - } - if i == start && wid == 1 && c == 'x' { // leading x for hex - start = i + 1 - wid = 4 - continue - } - switch c { - default: - return nil, &parseError{"invalid pattern syntax: " + pattern} - case '2', '3', '4', '5', '6', '7', '8', '9': - if wid != 4 { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - fallthrough - case '0', '1': - bits <<= wid - bits |= uint64(c - '0') - case 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F': - if wid != 4 { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - bits <<= 4 - bits |= uint64(c&^0x20 - 'A' + 10) - case 'y': - if i+1 < len(p) && (p[i+1] == '0' || p[i+1] == '1') { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - bits = 0 - case '+', '-': - if c == '+' && result == false { - // Have already seen a -. Should be - from here on. - return nil, &parseError{"invalid pattern syntax (+ after -): " + pattern} - } - if i > 0 { - n := (i - start) * wid - if n > 64 { - return nil, &parseError{"pattern bits too long: " + pattern} - } - if n <= 0 { - return nil, &parseError{"invalid pattern syntax: " + pattern} - } - if p[start] == 'y' { - n = 0 - } - mask := uint64(1)<= 0; i-- { - c := &m.list[i] - if id&c.mask == c.bits { - return c.result - } - } - return false -} - -// FileLine reports whether the change identified by file and line should be enabled. -// If the change should be printed, FileLine prints a one-line report to w. -func (m *Matcher) FileLine(w Writer, file string, line int) bool { - if m == nil { - return true - } - return m.fileLine(w, file, line) -} - -// fileLine does the real work for FileLine. -// This lets FileLine's body handle m == nil and potentially be inlined. -func (m *Matcher) fileLine(w Writer, file string, line int) bool { - h := Hash(file, line) - if m.ShouldPrint(h) { - if m.MarkerOnly() { - PrintMarker(w, h) - } else { - printFileLine(w, h, file, line) - } - } - return m.ShouldEnable(h) -} - -// printFileLine prints a non-marker-only report for file:line to w. -func printFileLine(w Writer, h uint64, file string, line int) error { - const markerLen = 40 // overestimate - b := make([]byte, 0, markerLen+len(file)+24) - b = AppendMarker(b, h) - b = appendFileLine(b, file, line) - b = append(b, '\n') - _, err := w.Write(b) - return err -} - -// appendFileLine appends file:line to dst, returning the extended slice. -func appendFileLine(dst []byte, file string, line int) []byte { - dst = append(dst, file...) - dst = append(dst, ':') - u := uint(line) - if line < 0 { - dst = append(dst, '-') - u = -u - } - var buf [24]byte - i := len(buf) - for i == len(buf) || u > 0 { - i-- - buf[i] = '0' + byte(u%10) - u /= 10 - } - dst = append(dst, buf[i:]...) - return dst -} - -// MatchStack assigns the current call stack a change ID. -// If the stack should be printed, MatchStack prints it. -// Then MatchStack reports whether a change at the current call stack should be enabled. -func (m *Matcher) Stack(w Writer) bool { - if m == nil { - return true - } - return m.stack(w) -} - -// stack does the real work for Stack. -// This lets stack's body handle m == nil and potentially be inlined. -func (m *Matcher) stack(w Writer) bool { - const maxStack = 16 - var stk [maxStack]uintptr - n := runtime.Callers(2, stk[:]) - // caller #2 is not for printing; need it to normalize PCs if ASLR. - if n <= 1 { - return false - } - - base := stk[0] - // normalize PCs - for i := range stk[:n] { - stk[i] -= base - } - - h := Hash(stk[:n]) - if m.ShouldPrint(h) { - var d *dedup - for { - d = m.dedup.Load() - if d != nil { - break - } - d = new(dedup) - if m.dedup.CompareAndSwap(nil, d) { - break - } - } - - if m.MarkerOnly() { - if !d.seenLossy(h) { - PrintMarker(w, h) - } - } else { - if !d.seen(h) { - // Restore PCs in stack for printing - for i := range stk[:n] { - stk[i] += base - } - printStack(w, h, stk[1:n]) - } - } - } - return m.ShouldEnable(h) -} - -// Writer is the same interface as io.Writer. -// It is duplicated here to avoid importing io. -type Writer interface { - Write([]byte) (int, error) -} - -// PrintMarker prints to w a one-line report containing only the marker for h. -// It is appropriate to use when [Matcher.ShouldPrint] and [Matcher.MarkerOnly] both return true. -func PrintMarker(w Writer, h uint64) error { - var buf [50]byte - b := AppendMarker(buf[:0], h) - b = append(b, '\n') - _, err := w.Write(b) - return err -} - -// printStack prints to w a multi-line report containing a formatting of the call stack stk, -// with each line preceded by the marker for h. -func printStack(w Writer, h uint64, stk []uintptr) error { - buf := make([]byte, 0, 2048) - - var prefixBuf [100]byte - prefix := AppendMarker(prefixBuf[:0], h) - - frames := runtime.CallersFrames(stk) - for { - f, more := frames.Next() - buf = append(buf, prefix...) - buf = append(buf, f.Function...) - buf = append(buf, "()\n"...) - buf = append(buf, prefix...) - buf = append(buf, '\t') - buf = appendFileLine(buf, f.File, f.Line) - buf = append(buf, '\n') - if !more { - break - } - } - buf = append(buf, prefix...) - buf = append(buf, '\n') - _, err := w.Write(buf) - return err -} - -// Marker returns the match marker text to use on any line reporting details -// about a match of the given ID. -// It always returns the hexadecimal format. -func Marker(id uint64) string { - return string(AppendMarker(nil, id)) -} - -// AppendMarker is like [Marker] but appends the marker to dst. -func AppendMarker(dst []byte, id uint64) []byte { - const prefix = "[bisect-match 0x" - var buf [len(prefix) + 16 + 1]byte - copy(buf[:], prefix) - for i := 0; i < 16; i++ { - buf[len(prefix)+i] = "0123456789abcdef"[id>>60] - id <<= 4 - } - buf[len(prefix)+16] = ']' - return append(dst, buf[:]...) -} - -// CutMarker finds the first match marker in line and removes it, -// returning the shortened line (with the marker removed), -// the ID from the match marker, -// and whether a marker was found at all. -// If there is no marker, CutMarker returns line, 0, false. -func CutMarker(line string) (short string, id uint64, ok bool) { - // Find first instance of prefix. - prefix := "[bisect-match " - i := 0 - for ; ; i++ { - if i >= len(line)-len(prefix) { - return line, 0, false - } - if line[i] == '[' && line[i:i+len(prefix)] == prefix { - break - } - } - - // Scan to ]. - j := i + len(prefix) - for j < len(line) && line[j] != ']' { - j++ - } - if j >= len(line) { - return line, 0, false - } - - // Parse id. - idstr := line[i+len(prefix) : j] - if len(idstr) >= 3 && idstr[:2] == "0x" { - // parse hex - if len(idstr) > 2+16 { // max 0x + 16 digits - return line, 0, false - } - for i := 2; i < len(idstr); i++ { - id <<= 4 - switch c := idstr[i]; { - case '0' <= c && c <= '9': - id |= uint64(c - '0') - case 'a' <= c && c <= 'f': - id |= uint64(c - 'a' + 10) - case 'A' <= c && c <= 'F': - id |= uint64(c - 'A' + 10) - } - } - } else { - if idstr == "" || len(idstr) > 64 { // min 1 digit, max 64 digits - return line, 0, false - } - // parse binary - for i := 0; i < len(idstr); i++ { - id <<= 1 - switch c := idstr[i]; c { - default: - return line, 0, false - case '0', '1': - id |= uint64(c - '0') - } - } - } - - // Construct shortened line. - // Remove at most one space from around the marker, - // so that "foo [marker] bar" shortens to "foo bar". - j++ // skip ] - if i > 0 && line[i-1] == ' ' { - i-- - } else if j < len(line) && line[j] == ' ' { - j++ - } - short = line[:i] + line[j:] - return short, id, true -} - -// Hash computes a hash of the data arguments, -// each of which must be of type string, byte, int, uint, int32, uint32, int64, uint64, uintptr, or a slice of one of those types. -func Hash(data ...any) uint64 { - h := offset64 - for _, v := range data { - switch v := v.(type) { - default: - // Note: Not printing the type, because reflect.ValueOf(v) - // would make the interfaces prepared by the caller escape - // and therefore allocate. This way, Hash(file, line) runs - // without any allocation. It should be clear from the - // source code calling Hash what the bad argument was. - panic("bisect.Hash: unexpected argument type") - case string: - h = fnvString(h, v) - case byte: - h = fnv(h, v) - case int: - h = fnvUint64(h, uint64(v)) - case uint: - h = fnvUint64(h, uint64(v)) - case int32: - h = fnvUint32(h, uint32(v)) - case uint32: - h = fnvUint32(h, v) - case int64: - h = fnvUint64(h, uint64(v)) - case uint64: - h = fnvUint64(h, v) - case uintptr: - h = fnvUint64(h, uint64(v)) - case []string: - for _, x := range v { - h = fnvString(h, x) - } - case []byte: - for _, x := range v { - h = fnv(h, x) - } - case []int: - for _, x := range v { - h = fnvUint64(h, uint64(x)) - } - case []uint: - for _, x := range v { - h = fnvUint64(h, uint64(x)) - } - case []int32: - for _, x := range v { - h = fnvUint32(h, uint32(x)) - } - case []uint32: - for _, x := range v { - h = fnvUint32(h, x) - } - case []int64: - for _, x := range v { - h = fnvUint64(h, uint64(x)) - } - case []uint64: - for _, x := range v { - h = fnvUint64(h, x) - } - case []uintptr: - for _, x := range v { - h = fnvUint64(h, uint64(x)) - } - } - } - return h -} - -// Trivial error implementation, here to avoid importing errors. - -// parseError is a trivial error implementation, -// defined here to avoid importing errors. -type parseError struct{ text string } - -func (e *parseError) Error() string { return e.text } - -// FNV-1a implementation. See Go's hash/fnv/fnv.go. -// Copied here for simplicity (can handle integers more directly) -// and to avoid importing hash/fnv. - -const ( - offset64 uint64 = 14695981039346656037 - prime64 uint64 = 1099511628211 -) - -func fnv(h uint64, x byte) uint64 { - h ^= uint64(x) - h *= prime64 - return h -} - -func fnvString(h uint64, x string) uint64 { - for i := 0; i < len(x); i++ { - h ^= uint64(x[i]) - h *= prime64 - } - return h -} - -func fnvUint64(h uint64, x uint64) uint64 { - for i := 0; i < 8; i++ { - h ^= x & 0xFF - x >>= 8 - h *= prime64 - } - return h -} - -func fnvUint32(h uint64, x uint32) uint64 { - for i := 0; i < 4; i++ { - h ^= uint64(x & 0xFF) - x >>= 8 - h *= prime64 - } - return h -} - -// A dedup is a deduplicator for call stacks, so that we only print -// a report for new call stacks, not for call stacks we've already -// reported. -// -// It has two modes: an approximate but lock-free mode that -// may still emit some duplicates, and a precise mode that uses -// a lock and never emits duplicates. -type dedup struct { - // 128-entry 4-way, lossy cache for seenLossy - recent [128][4]uint64 - - // complete history for seen - mu sync.Mutex - m map[uint64]bool -} - -// seen records that h has now been seen and reports whether it was seen before. -// When seen returns false, the caller is expected to print a report for h. -func (d *dedup) seen(h uint64) bool { - d.mu.Lock() - if d.m == nil { - d.m = make(map[uint64]bool) - } - seen := d.m[h] - d.m[h] = true - d.mu.Unlock() - return seen -} - -// seenLossy is a variant of seen that avoids a lock by using a cache of recently seen hashes. -// Each cache entry is N-way set-associative: h can appear in any of the slots. -// If h does not appear in any of them, then it is inserted into a random slot, -// overwriting whatever was there before. -func (d *dedup) seenLossy(h uint64) bool { - cache := &d.recent[uint(h)%uint(len(d.recent))] - for i := 0; i < len(cache); i++ { - if atomic.LoadUint64(&cache[i]) == h { - return true - } - } - - // Compute index in set to evict as hash of current set. - ch := offset64 - for _, x := range cache { - ch = fnvUint64(ch, x) - } - atomic.StoreUint64(&cache[uint(ch)%uint(len(cache))], h) - return false -} diff --git a/testing/internal/cfg/cfg.go b/testing/internal/cfg/cfg.go deleted file mode 100644 index 93297697..00000000 --- a/testing/internal/cfg/cfg.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 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 cfg holds configuration shared by the Go command and internal/testenv. -// Definitions that don't need to be exposed outside of cmd/go should be in -// cmd/go/internal/cfg instead of this package. -package cfg - -// KnownEnv is a list of environment variables that affect the operation -// of the Go command. -const KnownEnv = ` - AR - CC - CGO_CFLAGS - CGO_CFLAGS_ALLOW - CGO_CFLAGS_DISALLOW - CGO_CPPFLAGS - CGO_CPPFLAGS_ALLOW - CGO_CPPFLAGS_DISALLOW - CGO_CXXFLAGS - CGO_CXXFLAGS_ALLOW - CGO_CXXFLAGS_DISALLOW - CGO_ENABLED - CGO_FFLAGS - CGO_FFLAGS_ALLOW - CGO_FFLAGS_DISALLOW - CGO_LDFLAGS - CGO_LDFLAGS_ALLOW - CGO_LDFLAGS_DISALLOW - CXX - FC - GCCGO - GO111MODULE - GO386 - GOAMD64 - GOARCH - GOARM - GOARM64 - GOAUTH - GOBIN - GOCACHE - GOCACHEPROG - GOENV - GOEXE - GOEXPERIMENT - GOFIPS140 - GOFLAGS - GOGCCFLAGS - GOHOSTARCH - GOHOSTOS - GOINSECURE - GOMIPS - GOMIPS64 - GOMODCACHE - GONOPROXY - GONOSUMDB - GOOS - GOPATH - GOPPC64 - GOPRIVATE - GOPROXY - GORISCV64 - GOROOT - GOSUMDB - GOTMPDIR - GOTOOLCHAIN - GOTOOLDIR - GOVCS - GOWASM - GOWORK - GO_EXTLINK_ENABLED - PKG_CONFIG -` diff --git a/testing/internal/cpu/cpu.go b/testing/internal/cpu/cpu.go deleted file mode 100644 index 0acd8ffe..00000000 --- a/testing/internal/cpu/cpu.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2017 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 cpu implements processor feature detection -// used by the Go standard library. -package cpu - -import _ "unsafe" // for linkname - -// DebugOptions is set to true by the runtime if the OS supports reading -// GODEBUG early in runtime startup. -// This should not be changed after it is initialized. -var DebugOptions bool - -// CacheLinePad is used to pad structs to avoid false sharing. -type CacheLinePad struct{ _ [CacheLinePadSize]byte } - -// CacheLineSize is the CPU's assumed cache line size. -// There is currently no runtime detection of the real cache line size -// so we use the constant per GOARCH CacheLinePadSize as an approximation. -var CacheLineSize uintptr = CacheLinePadSize - -// The booleans in X86 contain the correspondingly named cpuid feature bit. -// HasAVX and HasAVX2 are only set if the OS does support XMM and YMM registers -// in addition to the cpuid feature bit being set. -// The struct is padded to avoid false sharing. -var X86 struct { - _ CacheLinePad - HasAES bool - HasADX bool - HasAVX bool - HasAVX2 bool - HasAVX512F bool - HasAVX512BW bool - HasAVX512VL bool - HasBMI1 bool - HasBMI2 bool - HasERMS bool - HasFSRM bool - HasFMA bool - HasOSXSAVE bool - HasPCLMULQDQ bool - HasPOPCNT bool - HasRDTSCP bool - HasSHA bool - HasSSE3 bool - HasSSSE3 bool - HasSSE41 bool - HasSSE42 bool - _ CacheLinePad -} - -// The booleans in ARM contain the correspondingly named cpu feature bit. -// The struct is padded to avoid false sharing. -var ARM struct { - _ CacheLinePad - HasVFPv4 bool - HasIDIVA bool - HasV7Atomics bool - _ CacheLinePad -} - -// The booleans in ARM64 contain the correspondingly named cpu feature bit. -// The struct is padded to avoid false sharing. -var ARM64 struct { - _ CacheLinePad - HasAES bool - HasPMULL bool - HasSHA1 bool - HasSHA2 bool - HasSHA512 bool - HasSHA3 bool - HasCRC32 bool - HasATOMICS bool - HasCPUID bool - HasDIT bool - IsNeoverse bool - _ CacheLinePad -} - -// The booleans in Loong64 contain the correspondingly named cpu feature bit. -// The struct is padded to avoid false sharing. -var Loong64 struct { - _ CacheLinePad - HasLSX bool // support 128-bit vector extension - HasLASX bool // support 256-bit vector extension - HasCRC32 bool // support CRC instruction - HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} - HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction - _ CacheLinePad -} - -var MIPS64X struct { - _ CacheLinePad - HasMSA bool // MIPS SIMD architecture - _ CacheLinePad -} - -// For ppc64(le), it is safe to check only for ISA level starting on ISA v3.00, -// since there are no optional categories. There are some exceptions that also -// require kernel support to work (darn, scv), so there are feature bits for -// those as well. The minimum processor requirement is POWER8 (ISA 2.07). -// The struct is padded to avoid false sharing. -var PPC64 struct { - _ CacheLinePad - HasDARN bool // Hardware random number generator (requires kernel enablement) - HasSCV bool // Syscall vectored (requires kernel enablement) - IsPOWER8 bool // ISA v2.07 (POWER8) - IsPOWER9 bool // ISA v3.00 (POWER9) - IsPOWER10 bool // ISA v3.1 (POWER10) - _ CacheLinePad -} - -var S390X struct { - _ CacheLinePad - HasZARCH bool // z architecture mode is active [mandatory] - HasSTFLE bool // store facility list extended [mandatory] - HasLDISP bool // long (20-bit) displacements [mandatory] - HasEIMM bool // 32-bit immediates [mandatory] - HasDFP bool // decimal floating point - HasETF3EH bool // ETF-3 enhanced - HasMSA bool // message security assist (CPACF) - HasAES bool // KM-AES{128,192,256} functions - HasAESCBC bool // KMC-AES{128,192,256} functions - HasAESCTR bool // KMCTR-AES{128,192,256} functions - HasAESGCM bool // KMA-GCM-AES{128,192,256} functions - HasGHASH bool // KIMD-GHASH function - HasSHA1 bool // K{I,L}MD-SHA-1 functions - HasSHA256 bool // K{I,L}MD-SHA-256 functions - HasSHA512 bool // K{I,L}MD-SHA-512 functions - HasSHA3 bool // K{I,L}MD-SHA3-{224,256,384,512} and K{I,L}MD-SHAKE-{128,256} functions - HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. - HasVXE bool // vector-enhancements facility 1 - HasKDSA bool // elliptic curve functions - HasECDSA bool // NIST curves - HasEDDSA bool // Edwards curves - _ CacheLinePad -} - -// RISCV64 contains the supported CPU features and performance characteristics for riscv64 -// platforms. The booleans in RISCV64, with the exception of HasFastMisaligned, indicate -// the presence of RISC-V extensions. -// The struct is padded to avoid false sharing. -var RISCV64 struct { - _ CacheLinePad - HasFastMisaligned bool // Fast misaligned accesses - HasV bool // Vector extension compatible with RVV 1.0 - HasZbb bool // Basic bit-manipulation extension - _ CacheLinePad -} - -// CPU feature variables are accessed by assembly code in various packages. -//go:linkname X86 -//go:linkname ARM -//go:linkname ARM64 -//go:linkname Loong64 -//go:linkname MIPS64X -//go:linkname PPC64 -//go:linkname S390X -//go:linkname RISCV64 - -// Initialize examines the processor and sets the relevant variables above. -// This is called by the runtime package early in program initialization, -// before normal init functions are run. env is set by runtime if the OS supports -// cpu feature options in GODEBUG. -func Initialize(env string) { - doinit() - processOptions(env) -} - -// options contains the cpu debug options that can be used in GODEBUG. -// Options are arch dependent and are added by the arch specific doinit functions. -// Features that are mandatory for the specific GOARCH should not be added to options -// (e.g. SSE2 on amd64). -var options []option - -// Option names should be lower case. e.g. avx instead of AVX. -type option struct { - Name string - Feature *bool - Specified bool // whether feature value was specified in GODEBUG - Enable bool // whether feature should be enabled -} - -// processOptions enables or disables CPU feature values based on the parsed env string. -// The env string is expected to be of the form cpu.feature1=value1,cpu.feature2=value2... -// where feature names is one of the architecture specific list stored in the -// cpu packages options variable and values are either 'on' or 'off'. -// If env contains cpu.all=off then all cpu features referenced through the options -// variable are disabled. Other feature names and values result in warning messages. -func processOptions(env string) { -field: - for env != "" { - field := "" - i := indexByte(env, ',') - if i < 0 { - field, env = env, "" - } else { - field, env = env[:i], env[i+1:] - } - if len(field) < 4 || field[:4] != "cpu." { - continue - } - i = indexByte(field, '=') - if i < 0 { - print("GODEBUG: no value specified for \"", field, "\"\n") - continue - } - key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" - - var enable bool - switch value { - case "on": - enable = true - case "off": - enable = false - default: - print("GODEBUG: value \"", value, "\" not supported for cpu option \"", key, "\"\n") - continue field - } - - if key == "all" { - for i := range options { - options[i].Specified = true - options[i].Enable = enable - } - continue field - } - - for i := range options { - if options[i].Name == key { - options[i].Specified = true - options[i].Enable = enable - continue field - } - } - - print("GODEBUG: unknown cpu feature \"", key, "\"\n") - } - - for _, o := range options { - if !o.Specified { - continue - } - - if o.Enable && !*o.Feature { - print("GODEBUG: can not enable \"", o.Name, "\", missing CPU support\n") - continue - } - - *o.Feature = o.Enable - } -} - -// indexByte returns the index of the first instance of c in s, -// or -1 if c is not present in s. -// indexByte is semantically the same as [strings.IndexByte]. -// We copy this function because "github.com/CodSpeedHQ/codspeed-go/testing/internal/cpu" should not have external dependencies. -func indexByte(s string, c byte) int { - for i := 0; i < len(s); i++ { - if s[i] == c { - return i - } - } - return -1 -} diff --git a/testing/internal/cpu/cpu.s b/testing/internal/cpu/cpu.s deleted file mode 100644 index 20166c8c..00000000 --- a/testing/internal/cpu/cpu.s +++ /dev/null @@ -1,6 +0,0 @@ -// 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. - -// This assembly file exists to allow internal/cpu to call -// non-exported runtime functions that use "go:linkname". diff --git a/testing/internal/cpu/cpu_arm.go b/testing/internal/cpu/cpu_arm.go deleted file mode 100644 index 080e7881..00000000 --- a/testing/internal/cpu/cpu_arm.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017 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 cpu - -const CacheLinePadSize = 32 - -// arm doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. -// These are initialized by archauxv() and should not be changed after they are -// initialized. -var HWCap uint -var HWCap2 uint -var Platform string - -// HWCAP/HWCAP2 bits. These are exposed by Linux and FreeBSD. -const ( - hwcap_VFPv4 = 1 << 16 - hwcap_IDIVA = 1 << 17 - hwcap_LPAE = 1 << 20 -) - -func doinit() { - options = []option{ - {Name: "vfpv4", Feature: &ARM.HasVFPv4}, - {Name: "idiva", Feature: &ARM.HasIDIVA}, - {Name: "v7atomics", Feature: &ARM.HasV7Atomics}, - } - - // HWCAP feature bits - ARM.HasVFPv4 = isSet(HWCap, hwcap_VFPv4) - ARM.HasIDIVA = isSet(HWCap, hwcap_IDIVA) - // lpae is required to make the 64-bit instructions LDRD and STRD (and variants) atomic. - // See ARMv7 manual section B1.6. - // We also need at least a v7 chip, for the DMB instruction. - ARM.HasV7Atomics = isSet(HWCap, hwcap_LPAE) && isV7(Platform) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} - -func isV7(s string) bool { - if s == "aarch64" { - return true - } - return s >= "v7" // will be something like v5, v7, v8, v8l -} diff --git a/testing/internal/cpu/cpu_arm64.go b/testing/internal/cpu/cpu_arm64.go deleted file mode 100644 index 7709966d..00000000 --- a/testing/internal/cpu/cpu_arm64.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2017 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 cpu - -// CacheLinePadSize is used to prevent false sharing of cache lines. -// We choose 128 because Apple Silicon, a.k.a. M1, has 128-byte cache line size. -// It doesn't cost much and is much more future-proof. -const CacheLinePadSize = 128 - -func doinit() { - options = []option{ - {Name: "aes", Feature: &ARM64.HasAES}, - {Name: "pmull", Feature: &ARM64.HasPMULL}, - {Name: "sha1", Feature: &ARM64.HasSHA1}, - {Name: "sha2", Feature: &ARM64.HasSHA2}, - {Name: "sha512", Feature: &ARM64.HasSHA512}, - {Name: "sha3", Feature: &ARM64.HasSHA3}, - {Name: "crc32", Feature: &ARM64.HasCRC32}, - {Name: "atomics", Feature: &ARM64.HasATOMICS}, - {Name: "cpuid", Feature: &ARM64.HasCPUID}, - {Name: "isNeoverse", Feature: &ARM64.IsNeoverse}, - } - - // arm64 uses different ways to detect CPU features at runtime depending on the operating system. - osInit() -} - -func getisar0() uint64 - -func getpfr0() uint64 - -func getMIDR() uint64 - -func extractBits(data uint64, start, end uint) uint { - return (uint)(data>>start) & ((1 << (end - start + 1)) - 1) -} - -func parseARM64SystemRegisters(isar0, pfr0 uint64) { - // ID_AA64ISAR0_EL1 - // https://developer.arm.com/documentation/ddi0601/2025-03/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0 - switch extractBits(isar0, 4, 7) { - case 1: - ARM64.HasAES = true - case 2: - ARM64.HasAES = true - ARM64.HasPMULL = true - } - - switch extractBits(isar0, 8, 11) { - case 1: - ARM64.HasSHA1 = true - } - - switch extractBits(isar0, 12, 15) { - case 1: - ARM64.HasSHA2 = true - case 2: - ARM64.HasSHA2 = true - ARM64.HasSHA512 = true - } - - switch extractBits(isar0, 16, 19) { - case 1: - ARM64.HasCRC32 = true - } - - switch extractBits(isar0, 20, 23) { - case 2: - ARM64.HasATOMICS = true - } - - switch extractBits(isar0, 32, 35) { - case 1: - ARM64.HasSHA3 = true - } - - switch extractBits(pfr0, 48, 51) { - case 1: - ARM64.HasDIT = true - } -} diff --git a/testing/internal/cpu/cpu_arm64.s b/testing/internal/cpu/cpu_arm64.s deleted file mode 100644 index 96075610..00000000 --- a/testing/internal/cpu/cpu_arm64.s +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -#include "textflag.h" - -// func getisar0() uint64 -TEXT ·getisar0(SB),NOSPLIT,$0 - // get Instruction Set Attributes 0 into R0 - MRS ID_AA64ISAR0_EL1, R0 - MOVD R0, ret+0(FP) - RET - -// func getpfr0() uint64 -TEXT ·getpfr0(SB),NOSPLIT,$0-8 - // get Processor Feature Register 0 into R0 - MRS ID_AA64PFR0_EL1, R0 - MOVD R0, ret+0(FP) - RET - -// func getMIDR() uint64 -TEXT ·getMIDR(SB), NOSPLIT, $0-8 - MRS MIDR_EL1, R0 - MOVD R0, ret+0(FP) - RET diff --git a/testing/internal/cpu/cpu_arm64_android.go b/testing/internal/cpu/cpu_arm64_android.go deleted file mode 100644 index fbdf7bac..00000000 --- a/testing/internal/cpu/cpu_arm64_android.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -//go:build arm64 - -package cpu - -func osInit() { - hwcapInit("android") -} diff --git a/testing/internal/cpu/cpu_arm64_darwin.go b/testing/internal/cpu/cpu_arm64_darwin.go deleted file mode 100644 index 28b47d60..00000000 --- a/testing/internal/cpu/cpu_arm64_darwin.go +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -//go:build arm64 && darwin && !ios - -package cpu - -import _ "unsafe" // for linkname - -func osInit() { - // macOS 12 moved these to the hw.optional.arm tree, but as of Go 1.24 we - // still support macOS 11. See [Determine Encryption Capabilities]. - // - // [Determine Encryption Capabilities]: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855 - ARM64.HasATOMICS = sysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) - ARM64.HasCRC32 = sysctlEnabled([]byte("hw.optional.armv8_crc32\x00")) - ARM64.HasSHA512 = sysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) - ARM64.HasSHA3 = sysctlEnabled([]byte("hw.optional.armv8_2_sha3\x00")) - - ARM64.HasDIT = sysctlEnabled([]byte("hw.optional.arm.FEAT_DIT\x00")) - - // There are no hw.optional sysctl values for the below features on macOS 11 - // to detect their supported state dynamically (although they are available - // in the hw.optional.arm tree on macOS 12). Assume the CPU features that - // Apple Silicon M1 supports to be available on all future iterations. - ARM64.HasAES = true - ARM64.HasPMULL = true - ARM64.HasSHA1 = true - ARM64.HasSHA2 = true -} - -//go:noescape -func getsysctlbyname(name []byte) (int32, int32) - -// sysctlEnabled should be an internal detail, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/bytedance/gopkg -// - github.com/songzhibin97/gkit -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -//go:linkname sysctlEnabled -func sysctlEnabled(name []byte) bool { - ret, value := getsysctlbyname(name) - if ret < 0 { - return false - } - return value > 0 -} diff --git a/testing/internal/cpu/cpu_arm64_freebsd.go b/testing/internal/cpu/cpu_arm64_freebsd.go deleted file mode 100644 index c339e6f2..00000000 --- a/testing/internal/cpu/cpu_arm64_freebsd.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -//go:build arm64 - -package cpu - -func osInit() { - // Retrieve info from system register ID_AA64ISAR0_EL1. - isar0 := getisar0() - prf0 := getpfr0() - - parseARM64SystemRegisters(isar0, prf0) -} diff --git a/testing/internal/cpu/cpu_arm64_hwcap.go b/testing/internal/cpu/cpu_arm64_hwcap.go deleted file mode 100644 index b6cc1f4d..00000000 --- a/testing/internal/cpu/cpu_arm64_hwcap.go +++ /dev/null @@ -1,88 +0,0 @@ -// 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. - -//go:build arm64 && linux - -package cpu - -import _ "unsafe" // for linkname - -// HWCap may be initialized by archauxv and -// should not be changed after it was initialized. -// -// Other widely used packages -// access HWCap using linkname as well, most notably: -// - github.com/klauspost/cpuid/v2 -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -//go:linkname HWCap -var HWCap uint - -// HWCAP bits. These are exposed by Linux. -// See arch/arm64/include/uapi/asm/hwcap.h. -const ( - hwcap_AES = 1 << 3 - hwcap_PMULL = 1 << 4 - hwcap_SHA1 = 1 << 5 - hwcap_SHA2 = 1 << 6 - hwcap_CRC32 = 1 << 7 - hwcap_ATOMICS = 1 << 8 - hwcap_CPUID = 1 << 11 - hwcap_SHA3 = 1 << 17 - hwcap_SHA512 = 1 << 21 - hwcap_DIT = 1 << 24 -) - -func hwcapInit(os string) { - // HWCap was populated by the runtime from the auxiliary vector. - // See https://docs.kernel.org/arch/arm64/elf_hwcaps.html. - // Use HWCap information since reading aarch64 system registers - // is not supported in user space on older linux kernels. - ARM64.HasAES = isSet(HWCap, hwcap_AES) - ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL) - ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1) - ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2) - ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3) - ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32) - ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID) - ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512) - ARM64.HasDIT = isSet(HWCap, hwcap_DIT) - - // The Samsung S9+ kernel reports support for atomics, but not all cores - // actually support them, resulting in SIGILL. See issue #28431. - // TODO(elias.naur): Only disable the optimization on bad chipsets on android. - ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) && os != "android" - - // Check to see if executing on a Neoverse core and in order to do that, - // check the AUXV for the CPUID bit. The getMIDR function executes an - // instruction which would normally be an illegal instruction, but it's - // trapped by the kernel, the value sanitized and then returned. - // Without the CPUID bit the kernel will not trap the instruction and the - // process will be terminated with SIGILL. - if ARM64.HasCPUID { - midr := getMIDR() - part_num := uint16((midr >> 4) & 0xfff) - implementer := byte((midr >> 24) & 0xff) - - // d0c - NeoverseN1 - // d40 - NeoverseV1 - // d49 - NeoverseN2 - // d4f - NeoverseV2 - // d8e - NeoverseN3 - // d84 - NeoverseV3 - // d83 - NeoverseV3ae - if implementer == 'A' { - switch part_num { - case 0xd0c, 0xd40, 0xd49, 0xd4f, 0xd8e, 0xd84, 0xd83: - ARM64.IsNeoverse = true - } - } - } -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/testing/internal/cpu/cpu_arm64_linux.go b/testing/internal/cpu/cpu_arm64_linux.go deleted file mode 100644 index d746bdb0..00000000 --- a/testing/internal/cpu/cpu_arm64_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -//go:build arm64 && linux && !android - -package cpu - -func osInit() { - hwcapInit("linux") -} diff --git a/testing/internal/cpu/cpu_arm64_openbsd.go b/testing/internal/cpu/cpu_arm64_openbsd.go deleted file mode 100644 index 6cc69c95..00000000 --- a/testing/internal/cpu/cpu_arm64_openbsd.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2022 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 arm64 - -package cpu - -const ( - // From OpenBSD's sys/sysctl.h. - _CTL_MACHDEP = 7 - - // From OpenBSD's machine/cpu.h. - _CPU_ID_AA64ISAR0 = 2 - _CPU_ID_AA64ISAR1 = 3 - _CPU_ID_AA64PFR0 = 8 -) - -//go:noescape -func sysctlUint64(mib []uint32) (uint64, bool) - -func osInit() { - // Get ID_AA64ISAR0 from sysctl. - isar0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64ISAR0}) - if !ok { - return - } - // Get ID_AA64PFR0 from sysctl. - pfr0, ok := sysctlUint64([]uint32{_CTL_MACHDEP, _CPU_ID_AA64PFR0}) - if !ok { - return - } - - parseARM64SystemRegisters(isar0, pfr0) -} diff --git a/testing/internal/cpu/cpu_arm64_other.go b/testing/internal/cpu/cpu_arm64_other.go deleted file mode 100644 index 44592cfc..00000000 --- a/testing/internal/cpu/cpu_arm64_other.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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. - -//go:build arm64 && !linux && !freebsd && !android && (!darwin || ios) && !openbsd - -package cpu - -func osInit() { - // Other operating systems do not support reading HWCap from auxiliary vector, - // reading privileged aarch64 system registers or sysctl in user space to detect - // CPU features at runtime. -} diff --git a/testing/internal/cpu/cpu_loong64.go b/testing/internal/cpu/cpu_loong64.go deleted file mode 100644 index de7eaf0c..00000000 --- a/testing/internal/cpu/cpu_loong64.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2022 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 loong64 - -package cpu - -// CacheLinePadSize is used to prevent false sharing of cache lines. -// We choose 64 because Loongson 3A5000 the L1 Dcache is 4-way 256-line 64-byte-per-line. -const CacheLinePadSize = 64 - -// Bit fields for CPUCFG registers, Related reference documents: -// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg -const ( - // CPUCFG1 bits - cpucfg1_CRC32 = 1 << 25 - - // CPUCFG2 bits - cpucfg2_LAM_BH = 1 << 27 - cpucfg2_LAMCAS = 1 << 28 -) - -// get_cpucfg is implemented in cpu_loong64.s. -func get_cpucfg(reg uint32) uint32 - -func doinit() { - options = []option{ - {Name: "lsx", Feature: &Loong64.HasLSX}, - {Name: "lasx", Feature: &Loong64.HasLASX}, - {Name: "crc32", Feature: &Loong64.HasCRC32}, - {Name: "lamcas", Feature: &Loong64.HasLAMCAS}, - {Name: "lam_bh", Feature: &Loong64.HasLAM_BH}, - } - - // The CPUCFG data on Loong64 only reflects the hardware capabilities, - // not the kernel support status, so features such as LSX and LASX that - // require kernel support cannot be obtained from the CPUCFG data. - // - // These features only require hardware capability support and do not - // require kernel specific support, so they can be obtained directly - // through CPUCFG - cfg1 := get_cpucfg(1) - cfg2 := get_cpucfg(2) - - Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32) - Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS) - Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH) - - osInit() -} - -func cfgIsSet(cfg uint32, val uint32) bool { - return cfg&val != 0 -} diff --git a/testing/internal/cpu/cpu_loong64.s b/testing/internal/cpu/cpu_loong64.s deleted file mode 100644 index f02a2780..00000000 --- a/testing/internal/cpu/cpu_loong64.s +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2024 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. - -#include "textflag.h" - -// func get_cpucfg(reg uint32) uint32 -TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0-12 - MOVW reg+0(FP), R5 - CPUCFG R5, R4 - MOVW R4, ret+8(FP) - RET diff --git a/testing/internal/cpu/cpu_loong64_hwcap.go b/testing/internal/cpu/cpu_loong64_hwcap.go deleted file mode 100644 index 2b25cc6b..00000000 --- a/testing/internal/cpu/cpu_loong64_hwcap.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2023 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 loong64 && linux - -package cpu - -// This is initialized by archauxv and should not be changed after it is -// initialized. -var HWCap uint - -// HWCAP bits. These are exposed by the Linux kernel. -const ( - hwcap_LOONGARCH_LSX = 1 << 4 - hwcap_LOONGARCH_LASX = 1 << 5 -) - -func hwcapInit() { - // TODO: Features that require kernel support like LSX and LASX can - // be detected here once needed in std library or by the compiler. - Loong64.HasLSX = hwcIsSet(HWCap, hwcap_LOONGARCH_LSX) - Loong64.HasLASX = hwcIsSet(HWCap, hwcap_LOONGARCH_LASX) -} - -func hwcIsSet(hwc uint, val uint) bool { - return hwc&val != 0 -} diff --git a/testing/internal/cpu/cpu_loong64_linux.go b/testing/internal/cpu/cpu_loong64_linux.go deleted file mode 100644 index 73bc384a..00000000 --- a/testing/internal/cpu/cpu_loong64_linux.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2023 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 loong64 && linux - -package cpu - -func osInit() { - hwcapInit() -} diff --git a/testing/internal/cpu/cpu_mips.go b/testing/internal/cpu/cpu_mips.go deleted file mode 100644 index 14a9c975..00000000 --- a/testing/internal/cpu/cpu_mips.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017 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 cpu - -const CacheLinePadSize = 32 - -func doinit() { -} diff --git a/testing/internal/cpu/cpu_mips64x.go b/testing/internal/cpu/cpu_mips64x.go deleted file mode 100644 index c452ffd8..00000000 --- a/testing/internal/cpu/cpu_mips64x.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 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 mips64 || mips64le - -package cpu - -const CacheLinePadSize = 32 - -// This is initialized by archauxv and should not be changed after it is -// initialized. -var HWCap uint - -// HWCAP bits. These are exposed by the Linux kernel 5.4. -const ( - // CPU features - hwcap_MIPS_MSA = 1 << 1 -) - -func doinit() { - options = []option{ - {Name: "msa", Feature: &MIPS64X.HasMSA}, - } - - // HWCAP feature bits - MIPS64X.HasMSA = isSet(HWCap, hwcap_MIPS_MSA) -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/testing/internal/cpu/cpu_mipsle.go b/testing/internal/cpu/cpu_mipsle.go deleted file mode 100644 index 14a9c975..00000000 --- a/testing/internal/cpu/cpu_mipsle.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2017 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 cpu - -const CacheLinePadSize = 32 - -func doinit() { -} diff --git a/testing/internal/cpu/cpu_no_name.go b/testing/internal/cpu/cpu_no_name.go deleted file mode 100644 index 2adfa1b7..00000000 --- a/testing/internal/cpu/cpu_no_name.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -//go:build !386 && !amd64 && !ppc64 && !ppc64le - -package cpu - -// Name returns the CPU name given by the vendor -// if it can be read directly from memory or by CPU instructions. -// If the CPU name can not be determined an empty string is returned. -// -// Implementations that use the Operating System (e.g. sysctl or /sys/) -// to gather CPU information for display should be placed in internal/sysinfo. -func Name() string { - // "A CPU has no name". - return "" -} diff --git a/testing/internal/cpu/cpu_ppc64x.go b/testing/internal/cpu/cpu_ppc64x.go deleted file mode 100644 index c4a08fe1..00000000 --- a/testing/internal/cpu/cpu_ppc64x.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2017 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 ppc64 || ppc64le - -package cpu - -const CacheLinePadSize = 128 - -func doinit() { - options = []option{ - {Name: "darn", Feature: &PPC64.HasDARN}, - {Name: "scv", Feature: &PPC64.HasSCV}, - {Name: "power9", Feature: &PPC64.IsPOWER9}, - } - - osinit() -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} - -func Name() string { - switch { - case PPC64.IsPOWER10: - return "POWER10" - case PPC64.IsPOWER9: - return "POWER9" - case PPC64.IsPOWER8: - return "POWER8" - } - return "" -} diff --git a/testing/internal/cpu/cpu_ppc64x_aix.go b/testing/internal/cpu/cpu_ppc64x_aix.go deleted file mode 100644 index f05ed6fa..00000000 --- a/testing/internal/cpu/cpu_ppc64x_aix.go +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -//go:build ppc64 || ppc64le - -package cpu - -const ( - // getsystemcfg constants - _SC_IMPL = 2 - _IMPL_POWER8 = 0x10000 - _IMPL_POWER9 = 0x20000 - _IMPL_POWER10 = 0x40000 -) - -func osinit() { - impl := getsystemcfg(_SC_IMPL) - PPC64.IsPOWER8 = isSet(impl, _IMPL_POWER8) - PPC64.IsPOWER9 = isSet(impl, _IMPL_POWER9) - PPC64.IsPOWER10 = isSet(impl, _IMPL_POWER10) -} - -// getsystemcfg is defined in runtime/os2_aix.go -func getsystemcfg(label uint) uint diff --git a/testing/internal/cpu/cpu_ppc64x_linux.go b/testing/internal/cpu/cpu_ppc64x_linux.go deleted file mode 100644 index 9df82ca8..00000000 --- a/testing/internal/cpu/cpu_ppc64x_linux.go +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -//go:build ppc64 || ppc64le - -package cpu - -// ppc64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. -// These are initialized by archauxv and should not be changed after they are -// initialized. -var HWCap uint -var HWCap2 uint - -// HWCAP bits. These are exposed by Linux. -const ( - // ISA Level - hwcap2_ARCH_2_07 = 0x80000000 - hwcap2_ARCH_3_00 = 0x00800000 - hwcap2_ARCH_3_1 = 0x00040000 - - // CPU features - hwcap2_DARN = 0x00200000 - hwcap2_SCV = 0x00100000 -) - -func osinit() { - PPC64.IsPOWER8 = isSet(HWCap2, hwcap2_ARCH_2_07) - PPC64.IsPOWER9 = isSet(HWCap2, hwcap2_ARCH_3_00) - PPC64.IsPOWER10 = isSet(HWCap2, hwcap2_ARCH_3_1) - PPC64.HasDARN = isSet(HWCap2, hwcap2_DARN) - PPC64.HasSCV = isSet(HWCap2, hwcap2_SCV) -} diff --git a/testing/internal/cpu/cpu_ppc64x_other.go b/testing/internal/cpu/cpu_ppc64x_other.go deleted file mode 100644 index d5b629db..00000000 --- a/testing/internal/cpu/cpu_ppc64x_other.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2023 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 (ppc64 || ppc64le) && !aix && !linux - -package cpu - -func osinit() { - // Other operating systems do not support reading HWCap from auxiliary vector, - // reading privileged system registers or sysctl in user space to detect CPU - // features at runtime. -} diff --git a/testing/internal/cpu/cpu_riscv64.go b/testing/internal/cpu/cpu_riscv64.go deleted file mode 100644 index 0fe17048..00000000 --- a/testing/internal/cpu/cpu_riscv64.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2019 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 cpu - -const CacheLinePadSize = 64 - -// RISC-V doesn't have a 'cpuid' equivalent. On Linux we rely on the riscv_hwprobe syscall. - -func doinit() { - options = []option{ - {Name: "fastmisaligned", Feature: &RISCV64.HasFastMisaligned}, - {Name: "v", Feature: &RISCV64.HasV}, - {Name: "zbb", Feature: &RISCV64.HasZbb}, - } - osInit() -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/testing/internal/cpu/cpu_riscv64_linux.go b/testing/internal/cpu/cpu_riscv64_linux.go deleted file mode 100644 index b67bdf58..00000000 --- a/testing/internal/cpu/cpu_riscv64_linux.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2024 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 riscv64 && linux - -package cpu - -import _ "unsafe" - -// RISC-V extension discovery code for Linux. -// -// A note on detection of the Vector extension using HWCAP. -// -// Support for the Vector extension version 1.0 was added to the Linux kernel in release 6.5. -// Support for the riscv_hwprobe syscall was added in 6.4. It follows that if the riscv_hwprobe -// syscall is not available then neither is the Vector extension (which needs kernel support). -// The riscv_hwprobe syscall should then be all we need to detect the Vector extension. -// However, some RISC-V board manufacturers ship boards with an older kernel on top of which -// they have back-ported various versions of the Vector extension patches but not the riscv_hwprobe -// patches. These kernels advertise support for the Vector extension using HWCAP. Falling -// back to HWCAP to detect the Vector extension, if riscv_hwprobe is not available, or simply not -// bothering with riscv_hwprobe at all and just using HWCAP may then seem like an attractive option. -// -// Unfortunately, simply checking the 'V' bit in AT_HWCAP will not work as this bit is used by -// RISC-V board and cloud instance providers to mean different things. The Lichee Pi 4A board -// and the Scaleway RV1 cloud instances use the 'V' bit to advertise their support for the unratified -// 0.7.1 version of the Vector Specification. The Banana Pi BPI-F3 and the CanMV-K230 board use -// it to advertise support for 1.0 of the Vector extension. Versions 0.7.1 and 1.0 of the Vector -// extension are binary incompatible. HWCAP can then not be used in isolation to populate the -// HasV field as this field indicates that the underlying CPU is compatible with RVV 1.0. -// Go will only support the ratified versions >= 1.0 and so any vector code it might generate -// would crash on a Scaleway RV1 instance or a Lichee Pi 4a, if allowed to run. -// -// There is a way at runtime to distinguish between versions 0.7.1 and 1.0 of the Vector -// specification by issuing a RVV 1.0 vsetvli instruction and checking the vill bit of the vtype -// register. This check would allow us to safely detect version 1.0 of the Vector extension -// with HWCAP, if riscv_hwprobe were not available. However, the check cannot -// be added until the assembler supports the Vector instructions. -// -// Note the riscv_hwprobe syscall does not suffer from these ambiguities by design as all of the -// extensions it advertises support for are explicitly versioned. It's also worth noting that -// the riscv_hwprobe syscall is the only way to detect multi-letter RISC-V extensions, e.g., Zvbb. -// These cannot be detected using HWCAP and so riscv_hwprobe must be used to detect the majority -// of RISC-V extensions. -// -// Please see https://docs.kernel.org/arch/riscv/hwprobe.html for more information. - -const ( - // Copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. - riscv_HWPROBE_KEY_IMA_EXT_0 = 0x4 - riscv_HWPROBE_IMA_V = 0x4 - riscv_HWPROBE_EXT_ZBB = 0x10 - riscv_HWPROBE_KEY_CPUPERF_0 = 0x5 - riscv_HWPROBE_MISALIGNED_FAST = 0x3 - riscv_HWPROBE_MISALIGNED_MASK = 0x7 -) - -// riscvHWProbePairs is copied from golang.org/x/sys/unix/ztypes_linux_riscv64.go. -type riscvHWProbePairs struct { - key int64 - value uint64 -} - -//go:linkname riscvHWProbe -func riscvHWProbe(pairs []riscvHWProbePairs, flags uint) bool - -func osInit() { - // A slice of key/value pair structures is passed to the RISCVHWProbe syscall. The key - // field should be initialised with one of the key constants defined above, e.g., - // RISCV_HWPROBE_KEY_IMA_EXT_0. The syscall will set the value field to the appropriate value. - // If the kernel does not recognise a key it will set the key field to -1 and the value field to 0. - - pairs := []riscvHWProbePairs{ - {riscv_HWPROBE_KEY_IMA_EXT_0, 0}, - {riscv_HWPROBE_KEY_CPUPERF_0, 0}, - } - - // This call only indicates that extensions are supported if they are implemented on all cores. - if !riscvHWProbe(pairs, 0) { - return - } - - if pairs[0].key != -1 { - v := uint(pairs[0].value) - RISCV64.HasV = isSet(v, riscv_HWPROBE_IMA_V) - RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB) - } - if pairs[1].key != -1 { - v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK - RISCV64.HasFastMisaligned = v == riscv_HWPROBE_MISALIGNED_FAST - } -} diff --git a/testing/internal/cpu/cpu_riscv64_other.go b/testing/internal/cpu/cpu_riscv64_other.go deleted file mode 100644 index 1307d822..00000000 --- a/testing/internal/cpu/cpu_riscv64_other.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024 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 riscv64 && !linux - -package cpu - -func osInit() { - // Other operating systems do not support the riscv_hwprobe syscall. -} diff --git a/testing/internal/cpu/cpu_s390x.go b/testing/internal/cpu/cpu_s390x.go deleted file mode 100644 index 45d8ed27..00000000 --- a/testing/internal/cpu/cpu_s390x.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2017 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 cpu - -const CacheLinePadSize = 256 - -var HWCap uint - -// bitIsSet reports whether the bit at index is set. The bit index -// is in big endian order, so bit index 0 is the leftmost bit. -func bitIsSet(bits []uint64, index uint) bool { - return bits[index/64]&((1<<63)>>(index%64)) != 0 -} - -// function is the function code for the named function. -type function uint8 - -const ( - // KM{,A,C,CTR} function codes - aes128 function = 18 // AES-128 - aes192 function = 19 // AES-192 - aes256 function = 20 // AES-256 - - // K{I,L}MD function codes - sha1 function = 1 // SHA-1 - sha256 function = 2 // SHA-256 - sha512 function = 3 // SHA-512 - sha3_224 function = 32 // SHA3-224 - sha3_256 function = 33 // SHA3-256 - sha3_384 function = 34 // SHA3-384 - sha3_512 function = 35 // SHA3-512 - shake128 function = 36 // SHAKE-128 - shake256 function = 37 // SHAKE-256 - - // KLMD function codes - ghash function = 65 // GHASH -) - -const ( - // KDSA function codes - ecdsaVerifyP256 function = 1 // NIST P256 - ecdsaVerifyP384 function = 2 // NIST P384 - ecdsaVerifyP521 function = 3 // NIST P521 - ecdsaSignP256 function = 9 // NIST P256 - ecdsaSignP384 function = 10 // NIST P384 - ecdsaSignP521 function = 11 // NIST P521 - eddsaVerifyEd25519 function = 32 // Curve25519 - eddsaVerifyEd448 function = 36 // Curve448 - eddsaSignEd25519 function = 40 // Curve25519 - eddsaSignEd448 function = 44 // Curve448 -) - -// queryResult contains the result of a Query function -// call. Bits are numbered in big endian order so the -// leftmost bit (the MSB) is at index 0. -type queryResult struct { - bits [2]uint64 -} - -// Has reports whether the given functions are present. -func (q *queryResult) Has(fns ...function) bool { - if len(fns) == 0 { - panic("no function codes provided") - } - for _, f := range fns { - if !bitIsSet(q.bits[:], uint(f)) { - return false - } - } - return true -} - -// facility is a bit index for the named facility. -type facility uint8 - -const ( - // mandatory facilities - zarch facility = 1 // z architecture mode is active - stflef facility = 7 // store-facility-list-extended - ldisp facility = 18 // long-displacement - eimm facility = 21 // extended-immediate - - // miscellaneous facilities - dfp facility = 42 // decimal-floating-point - etf3eh facility = 30 // extended-translation 3 enhancement - - // cryptography facilities - msa facility = 17 // message-security-assist - msa3 facility = 76 // message-security-assist extension 3 - msa4 facility = 77 // message-security-assist extension 4 - msa5 facility = 57 // message-security-assist extension 5 - msa8 facility = 146 // message-security-assist extension 8 - msa9 facility = 155 // message-security-assist extension 9 - - // vector facilities - vxe facility = 135 // vector-enhancements 1 - - // Note: vx requires kernel support - // and so must be fetched from HWCAP. - - hwcap_VX = 1 << 11 // vector facility -) - -// facilityList contains the result of an STFLE call. -// Bits are numbered in big endian order so the -// leftmost bit (the MSB) is at index 0. -type facilityList struct { - bits [4]uint64 -} - -// Has reports whether the given facilities are present. -func (s *facilityList) Has(fs ...facility) bool { - if len(fs) == 0 { - panic("no facility bits provided") - } - for _, f := range fs { - if !bitIsSet(s.bits[:], uint(f)) { - return false - } - } - return true -} - -// The following feature detection functions are defined in cpu_s390x.s. -// They are likely to be expensive to call so the results should be cached. -func stfle() facilityList -func kmQuery() queryResult -func kmcQuery() queryResult -func kmctrQuery() queryResult -func kmaQuery() queryResult -func kimdQuery() queryResult -func klmdQuery() queryResult -func kdsaQuery() queryResult - -func doinit() { - options = []option{ - {Name: "zarch", Feature: &S390X.HasZARCH}, - {Name: "stfle", Feature: &S390X.HasSTFLE}, - {Name: "ldisp", Feature: &S390X.HasLDISP}, - {Name: "msa", Feature: &S390X.HasMSA}, - {Name: "eimm", Feature: &S390X.HasEIMM}, - {Name: "dfp", Feature: &S390X.HasDFP}, - {Name: "etf3eh", Feature: &S390X.HasETF3EH}, - {Name: "vx", Feature: &S390X.HasVX}, - {Name: "vxe", Feature: &S390X.HasVXE}, - {Name: "kdsa", Feature: &S390X.HasKDSA}, - } - - aes := []function{aes128, aes192, aes256} - facilities := stfle() - - S390X.HasZARCH = facilities.Has(zarch) - S390X.HasSTFLE = facilities.Has(stflef) - S390X.HasLDISP = facilities.Has(ldisp) - S390X.HasEIMM = facilities.Has(eimm) - S390X.HasDFP = facilities.Has(dfp) - S390X.HasETF3EH = facilities.Has(etf3eh) - S390X.HasMSA = facilities.Has(msa) - - if S390X.HasMSA { - // cipher message - km, kmc := kmQuery(), kmcQuery() - S390X.HasAES = km.Has(aes...) - S390X.HasAESCBC = kmc.Has(aes...) - if facilities.Has(msa4) { - kmctr := kmctrQuery() - S390X.HasAESCTR = kmctr.Has(aes...) - } - if facilities.Has(msa8) { - kma := kmaQuery() - S390X.HasAESGCM = kma.Has(aes...) - } - - // compute message digest - kimd := kimdQuery() // intermediate (no padding) - klmd := klmdQuery() // last (padding) - S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) - S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) - S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) - S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist - sha3 := []function{ - sha3_224, sha3_256, sha3_384, sha3_512, - shake128, shake256, - } - S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) - S390X.HasKDSA = facilities.Has(msa9) // elliptic curves - if S390X.HasKDSA { - kdsa := kdsaQuery() - S390X.HasECDSA = kdsa.Has(ecdsaVerifyP256, ecdsaSignP256, ecdsaVerifyP384, ecdsaSignP384, ecdsaVerifyP521, ecdsaSignP521) - S390X.HasEDDSA = kdsa.Has(eddsaVerifyEd25519, eddsaSignEd25519, eddsaVerifyEd448, eddsaSignEd448) - } - } - - S390X.HasVX = isSet(HWCap, hwcap_VX) - - if S390X.HasVX { - S390X.HasVXE = facilities.Has(vxe) - } -} - -func isSet(hwc uint, value uint) bool { - return hwc&value != 0 -} diff --git a/testing/internal/cpu/cpu_s390x.s b/testing/internal/cpu/cpu_s390x.s deleted file mode 100644 index 488553c3..00000000 --- a/testing/internal/cpu/cpu_s390x.s +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 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. - -#include "textflag.h" - -// func stfle() facilityList -TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32 - MOVD $ret+0(FP), R1 - MOVD $3, R0 // last doubleword index to store - XC $32, (R1), (R1) // clear 4 doublewords (32 bytes) - WORD $0xb2b01000 // store facility list extended (STFLE) - RET - -// func kmQuery() queryResult -TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KM-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KM R2, R4 // cipher message (KM) - RET - -// func kmcQuery() queryResult -TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMC-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KMC R2, R4 // cipher message with chaining (KMC) - RET - -// func kmctrQuery() queryResult -TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMCTR-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KMCTR R2, R4, R4 // cipher message with counter (KMCTR) - RET - -// func kmaQuery() queryResult -TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KMA-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KMA R2, R6, R4 // cipher message with authentication (KMA) - RET - -// func kimdQuery() queryResult -TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KIMD-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KIMD R2, R4 // compute intermediate message digest (KIMD) - RET - -// func klmdQuery() queryResult -TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KLMD-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KLMD R2, R4 // compute last message digest (KLMD) - RET - -// func kdsaQuery() queryResult -TEXT ·kdsaQuery(SB), NOSPLIT|NOFRAME, $0-16 - MOVD $0, R0 // set function code to 0 (KLMD-Query) - MOVD $ret+0(FP), R1 // address of 16-byte return value - KDSA R0, R4 // compute digital signature authentication - RET diff --git a/testing/internal/cpu/cpu_s390x_test.go b/testing/internal/cpu/cpu_s390x_test.go deleted file mode 100644 index 07086f8d..00000000 --- a/testing/internal/cpu/cpu_s390x_test.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 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 cpu_test - -import ( - "errors" - . "github.com/CodSpeedHQ/codspeed-go/testing/internal/cpu" - "os" - "regexp" - "testing" -) - -func getFeatureList() ([]string, error) { - cpuinfo, err := os.ReadFile("/proc/cpuinfo") - if err != nil { - return nil, err - } - r := regexp.MustCompile("features\\s*:\\s*(.*)") - b := r.FindSubmatch(cpuinfo) - if len(b) < 2 { - return nil, errors.New("no feature list in /proc/cpuinfo") - } - return regexp.MustCompile("\\s+").Split(string(b[1]), -1), nil -} - -func TestS390XAgainstCPUInfo(t *testing.T) { - // mapping of linux feature strings to S390X fields - mapping := make(map[string]*bool) - for _, option := range Options { - mapping[option.Name] = option.Feature - } - - // these must be true on the machines Go supports - mandatory := make(map[string]bool) - mandatory["zarch"] = false - mandatory["eimm"] = false - mandatory["ldisp"] = false - mandatory["stfle"] = false - - features, err := getFeatureList() - if err != nil { - t.Error(err) - } - for _, feature := range features { - if _, ok := mandatory[feature]; ok { - mandatory[feature] = true - } - if flag, ok := mapping[feature]; ok { - if !*flag { - t.Errorf("feature '%v' not detected", feature) - } - } else { - t.Logf("no entry for '%v'", feature) - } - } - for k, v := range mandatory { - if !v { - t.Errorf("mandatory feature '%v' not detected", k) - } - } -} diff --git a/testing/internal/cpu/cpu_test.go b/testing/internal/cpu/cpu_test.go deleted file mode 100644 index 1d05f31d..00000000 --- a/testing/internal/cpu/cpu_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2017 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 cpu_test - -import ( - . "github.com/CodSpeedHQ/codspeed-go/testing/internal/cpu" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebug" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os/exec" - "testing" -) - -func MustHaveDebugOptionsSupport(t *testing.T) { - if !DebugOptions { - t.Skipf("skipping test: cpu feature options not supported by OS") - } -} - -func MustSupportFeatureDetection(t *testing.T) { - // TODO: add platforms that do not have CPU feature detection support. -} - -func runDebugOptionsTest(t *testing.T, test string, options string) { - MustHaveDebugOptionsSupport(t) - - env := "GODEBUG=" + options - - cmd := exec.Command(testenv.Executable(t), "-test.run=^"+test+"$") - cmd.Env = append(cmd.Env, env) - - output, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%s with %s: run failed: %v output:\n%s\n", - test, env, err, string(output)) - } -} - -func TestDisableAllCapabilities(t *testing.T) { - MustSupportFeatureDetection(t) - runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "cpu.all=off") -} - -func TestAllCapabilitiesDisabled(t *testing.T) { - MustHaveDebugOptionsSupport(t) - - if godebug.New("#cpu.all").Value() != "off" { - t.Skipf("skipping test: GODEBUG=cpu.all=off not set") - } - - for _, o := range Options { - want := false - if got := *o.Feature; got != want { - t.Errorf("%v: expected %v, got %v", o.Name, want, got) - } - } -} diff --git a/testing/internal/cpu/cpu_wasm.go b/testing/internal/cpu/cpu_wasm.go deleted file mode 100644 index 2310ad6a..00000000 --- a/testing/internal/cpu/cpu_wasm.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 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 cpu - -const CacheLinePadSize = 64 - -func doinit() { -} diff --git a/testing/internal/cpu/cpu_x86.go b/testing/internal/cpu/cpu_x86.go deleted file mode 100644 index ee812076..00000000 --- a/testing/internal/cpu/cpu_x86.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2017 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 386 || amd64 - -package cpu - -const CacheLinePadSize = 64 - -// cpuid is implemented in cpu_x86.s. -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) - -// xgetbv with ecx = 0 is implemented in cpu_x86.s. -func xgetbv() (eax, edx uint32) - -// getGOAMD64level is implemented in cpu_x86.s. Returns number in [1,4]. -func getGOAMD64level() int32 - -const ( - // ecx bits - cpuid_SSE3 = 1 << 0 - cpuid_PCLMULQDQ = 1 << 1 - cpuid_SSSE3 = 1 << 9 - cpuid_FMA = 1 << 12 - cpuid_SSE41 = 1 << 19 - cpuid_SSE42 = 1 << 20 - cpuid_POPCNT = 1 << 23 - cpuid_AES = 1 << 25 - cpuid_OSXSAVE = 1 << 27 - cpuid_AVX = 1 << 28 - - // ebx bits - cpuid_BMI1 = 1 << 3 - cpuid_AVX2 = 1 << 5 - cpuid_BMI2 = 1 << 8 - cpuid_ERMS = 1 << 9 - cpuid_AVX512F = 1 << 16 - cpuid_ADX = 1 << 19 - cpuid_SHA = 1 << 29 - cpuid_AVX512BW = 1 << 30 - cpuid_AVX512VL = 1 << 31 - // edx bits - cpuid_FSRM = 1 << 4 - // edx bits for CPUID 0x80000001 - cpuid_RDTSCP = 1 << 27 -) - -var maxExtendedFunctionInformation uint32 - -func doinit() { - options = []option{ - {Name: "adx", Feature: &X86.HasADX}, - {Name: "aes", Feature: &X86.HasAES}, - {Name: "erms", Feature: &X86.HasERMS}, - {Name: "fsrm", Feature: &X86.HasFSRM}, - {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, - {Name: "rdtscp", Feature: &X86.HasRDTSCP}, - {Name: "sha", Feature: &X86.HasSHA}, - } - level := getGOAMD64level() - if level < 2 { - // These options are required at level 2. At lower levels - // they can be turned off. - options = append(options, - option{Name: "popcnt", Feature: &X86.HasPOPCNT}, - option{Name: "sse3", Feature: &X86.HasSSE3}, - option{Name: "sse41", Feature: &X86.HasSSE41}, - option{Name: "sse42", Feature: &X86.HasSSE42}, - option{Name: "ssse3", Feature: &X86.HasSSSE3}) - } - if level < 3 { - // These options are required at level 3. At lower levels - // they can be turned off. - options = append(options, - option{Name: "avx", Feature: &X86.HasAVX}, - option{Name: "avx2", Feature: &X86.HasAVX2}, - option{Name: "bmi1", Feature: &X86.HasBMI1}, - option{Name: "bmi2", Feature: &X86.HasBMI2}, - option{Name: "fma", Feature: &X86.HasFMA}) - } - if level < 4 { - // These options are required at level 4. At lower levels - // they can be turned off. - options = append(options, - option{Name: "avx512f", Feature: &X86.HasAVX512F}, - option{Name: "avx512bw", Feature: &X86.HasAVX512BW}, - option{Name: "avx512vl", Feature: &X86.HasAVX512VL}, - ) - } - - maxID, _, _, _ := cpuid(0, 0) - - if maxID < 1 { - return - } - - maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0) - - _, _, ecx1, _ := cpuid(1, 0) - - X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) - X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) - X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) - X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) - X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) - X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) - X86.HasAES = isSet(ecx1, cpuid_AES) - - // OSXSAVE can be false when using older Operating Systems - // or when explicitly disabled on newer Operating Systems by - // e.g. setting the xsavedisable boot option on Windows 10. - X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) - - // The FMA instruction set extension only has VEX prefixed instructions. - // VEX prefixed instructions require OSXSAVE to be enabled. - // See Intel 64 and IA-32 Architecture Software Developer’s Manual Volume 2 - // Section 2.4 "AVX and SSE Instruction Exception Specification" - X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE - - osSupportsAVX := false - osSupportsAVX512 := false - // For XGETBV, OSXSAVE bit is required and sufficient. - if X86.HasOSXSAVE { - eax, _ := xgetbv() - // Check if XMM and YMM registers have OS support. - osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) - - // AVX512 detection does not work on Darwin, - // see https://github.com/golang/go/issues/49233 - // - // Check if opmask, ZMMhi256 and Hi16_ZMM have OS support. - osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7) - } - - X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX - - if maxID < 7 { - return - } - - _, ebx7, _, edx7 := cpuid(7, 0) - X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) - X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX - X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) - X86.HasERMS = isSet(ebx7, cpuid_ERMS) - X86.HasADX = isSet(ebx7, cpuid_ADX) - X86.HasSHA = isSet(ebx7, cpuid_SHA) - - X86.HasAVX512F = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 - if X86.HasAVX512F { - X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW) - X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL) - } - - X86.HasFSRM = isSet(edx7, cpuid_FSRM) - - var maxExtendedInformation uint32 - maxExtendedInformation, _, _, _ = cpuid(0x80000000, 0) - - if maxExtendedInformation < 0x80000001 { - return - } - - _, _, _, edxExt1 := cpuid(0x80000001, 0) - X86.HasRDTSCP = isSet(edxExt1, cpuid_RDTSCP) -} - -func isSet(hwc uint32, value uint32) bool { - return hwc&value != 0 -} - -// Name returns the CPU name given by the vendor. -// If the CPU name can not be determined an -// empty string is returned. -func Name() string { - if maxExtendedFunctionInformation < 0x80000004 { - return "" - } - - data := make([]byte, 0, 3*4*4) - - var eax, ebx, ecx, edx uint32 - eax, ebx, ecx, edx = cpuid(0x80000002, 0) - data = appendBytes(data, eax, ebx, ecx, edx) - eax, ebx, ecx, edx = cpuid(0x80000003, 0) - data = appendBytes(data, eax, ebx, ecx, edx) - eax, ebx, ecx, edx = cpuid(0x80000004, 0) - data = appendBytes(data, eax, ebx, ecx, edx) - - // Trim leading spaces. - for len(data) > 0 && data[0] == ' ' { - data = data[1:] - } - - // Trim tail after and including the first null byte. - for i, c := range data { - if c == '\x00' { - data = data[:i] - break - } - } - - return string(data) -} - -func appendBytes(b []byte, args ...uint32) []byte { - for _, arg := range args { - b = append(b, - byte((arg >> 0)), - byte((arg >> 8)), - byte((arg >> 16)), - byte((arg >> 24))) - } - return b -} diff --git a/testing/internal/cpu/cpu_x86.s b/testing/internal/cpu/cpu_x86.s deleted file mode 100644 index 2ee8eca2..00000000 --- a/testing/internal/cpu/cpu_x86.s +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 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 386 || amd64 - -#include "textflag.h" - -// func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuid(SB), NOSPLIT, $0-24 - MOVL eaxArg+0(FP), AX - MOVL ecxArg+4(FP), CX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET - -// func xgetbv() (eax, edx uint32) -TEXT ·xgetbv(SB),NOSPLIT,$0-8 - MOVL $0, CX - XGETBV - MOVL AX, eax+0(FP) - MOVL DX, edx+4(FP) - RET - -// func getGOAMD64level() int32 -TEXT ·getGOAMD64level(SB),NOSPLIT,$0-4 -#ifdef GOAMD64_v4 - MOVL $4, ret+0(FP) -#else -#ifdef GOAMD64_v3 - MOVL $3, ret+0(FP) -#else -#ifdef GOAMD64_v2 - MOVL $2, ret+0(FP) -#else - MOVL $1, ret+0(FP) -#endif -#endif -#endif - RET diff --git a/testing/internal/cpu/cpu_x86_test.go b/testing/internal/cpu/cpu_x86_test.go deleted file mode 100644 index 2c0e2e5c..00000000 --- a/testing/internal/cpu/cpu_x86_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2018 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 386 || amd64 - -package cpu_test - -import ( - . "github.com/CodSpeedHQ/codspeed-go/testing/internal/cpu" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebug" - "testing" -) - -func TestX86ifAVX2hasAVX(t *testing.T) { - if X86.HasAVX2 && !X86.HasAVX { - t.Fatalf("HasAVX expected true when HasAVX2 is true, got false") - } -} - -func TestX86ifAVX512FhasAVX2(t *testing.T) { - if X86.HasAVX512F && !X86.HasAVX2 { - t.Fatalf("HasAVX2 expected true when HasAVX512F is true, got false") - } -} - -func TestX86ifAVX512BWhasAVX512F(t *testing.T) { - if X86.HasAVX512BW && !X86.HasAVX512F { - t.Fatalf("HasAVX512F expected true when HasAVX512BW is true, got false") - } -} - -func TestX86ifAVX512VLhasAVX512F(t *testing.T) { - if X86.HasAVX512VL && !X86.HasAVX512F { - t.Fatalf("HasAVX512F expected true when HasAVX512VL is true, got false") - } -} - -func TestDisableSSE3(t *testing.T) { - if GetGOAMD64level() > 1 { - t.Skip("skipping test: can't run on GOAMD64>v1 machines") - } - runDebugOptionsTest(t, "TestSSE3DebugOption", "cpu.sse3=off") -} - -func TestSSE3DebugOption(t *testing.T) { - MustHaveDebugOptionsSupport(t) - - if godebug.New("#cpu.sse3").Value() != "off" { - t.Skipf("skipping test: GODEBUG=cpu.sse3=off not set") - } - - want := false - if got := X86.HasSSE3; got != want { - t.Errorf("X86.HasSSE3 expected %v, got %v", want, got) - } -} diff --git a/testing/internal/cpu/export_test.go b/testing/internal/cpu/export_test.go deleted file mode 100644 index 91bfc1bb..00000000 --- a/testing/internal/cpu/export_test.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2018 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 cpu - -var ( - Options = options -) diff --git a/testing/internal/cpu/export_x86_test.go b/testing/internal/cpu/export_x86_test.go deleted file mode 100644 index a12b6f27..00000000 --- a/testing/internal/cpu/export_x86_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2022 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 386 || amd64 - -package cpu - -var ( - GetGOAMD64level = getGOAMD64level -) diff --git a/testing/internal/diff/diff.go b/testing/internal/diff/diff.go deleted file mode 100644 index 6a40b23f..00000000 --- a/testing/internal/diff/diff.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2022 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 diff - -import ( - "bytes" - "fmt" - "sort" - "strings" -) - -// A pair is a pair of values tracked for both the x and y side of a diff. -// It is typically a pair of line indexes. -type pair struct{ x, y int } - -// Diff returns an anchored diff of the two texts old and new -// in the “unified diff” format. If old and new are identical, -// Diff returns a nil slice (no output). -// -// Unix diff implementations typically look for a diff with -// the smallest number of lines inserted and removed, -// which can in the worst case take time quadratic in the -// number of lines in the texts. As a result, many implementations -// either can be made to run for a long time or cut off the search -// after a predetermined amount of work. -// -// In contrast, this implementation looks for a diff with the -// smallest number of “unique” lines inserted and removed, -// where unique means a line that appears just once in both old and new. -// We call this an “anchored diff” because the unique lines anchor -// the chosen matching regions. An anchored diff is usually clearer -// than a standard diff, because the algorithm does not try to -// reuse unrelated blank lines or closing braces. -// The algorithm also guarantees to run in O(n log n) time -// instead of the standard O(n²) time. -// -// Some systems call this approach a “patience diff,” named for -// the “patience sorting” algorithm, itself named for a solitaire card game. -// We avoid that name for two reasons. First, the name has been used -// for a few different variants of the algorithm, so it is imprecise. -// Second, the name is frequently interpreted as meaning that you have -// to wait longer (to be patient) for the diff, meaning that it is a slower algorithm, -// when in fact the algorithm is faster than the standard one. -func Diff(oldName string, old []byte, newName string, new []byte) []byte { - if bytes.Equal(old, new) { - return nil - } - x := lines(old) - y := lines(new) - - // Print diff header. - var out bytes.Buffer - fmt.Fprintf(&out, "diff %s %s\n", oldName, newName) - fmt.Fprintf(&out, "--- %s\n", oldName) - fmt.Fprintf(&out, "+++ %s\n", newName) - - // Loop over matches to consider, - // expanding each match to include surrounding lines, - // and then printing diff chunks. - // To avoid setup/teardown cases outside the loop, - // tgs returns a leading {0,0} and trailing {len(x), len(y)} pair - // in the sequence of matches. - var ( - done pair // printed up to x[:done.x] and y[:done.y] - chunk pair // start lines of current chunk - count pair // number of lines from each side in current chunk - ctext []string // lines for current chunk - ) - for _, m := range tgs(x, y) { - if m.x < done.x { - // Already handled scanning forward from earlier match. - continue - } - - // Expand matching lines as far as possible, - // establishing that x[start.x:end.x] == y[start.y:end.y]. - // Note that on the first (or last) iteration we may (or definitely do) - // have an empty match: start.x==end.x and start.y==end.y. - start := m - for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] { - start.x-- - start.y-- - } - end := m - for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] { - end.x++ - end.y++ - } - - // Emit the mismatched lines before start into this chunk. - // (No effect on first sentinel iteration, when start = {0,0}.) - for _, s := range x[done.x:start.x] { - ctext = append(ctext, "-"+s) - count.x++ - } - for _, s := range y[done.y:start.y] { - ctext = append(ctext, "+"+s) - count.y++ - } - - // If we're not at EOF and have too few common lines, - // the chunk includes all the common lines and continues. - const C = 3 // number of context lines - if (end.x < len(x) || end.y < len(y)) && - (end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) { - for _, s := range x[start.x:end.x] { - ctext = append(ctext, " "+s) - count.x++ - count.y++ - } - done = end - continue - } - - // End chunk with common lines for context. - if len(ctext) > 0 { - n := end.x - start.x - if n > C { - n = C - } - for _, s := range x[start.x : start.x+n] { - ctext = append(ctext, " "+s) - count.x++ - count.y++ - } - done = pair{start.x + n, start.y + n} - - // Format and emit chunk. - // Convert line numbers to 1-indexed. - // Special case: empty file shows up as 0,0 not 1,0. - if count.x > 0 { - chunk.x++ - } - if count.y > 0 { - chunk.y++ - } - fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y) - for _, s := range ctext { - out.WriteString(s) - } - count.x = 0 - count.y = 0 - ctext = ctext[:0] - } - - // If we reached EOF, we're done. - if end.x >= len(x) && end.y >= len(y) { - break - } - - // Otherwise start a new chunk. - chunk = pair{end.x - C, end.y - C} - for _, s := range x[chunk.x:end.x] { - ctext = append(ctext, " "+s) - count.x++ - count.y++ - } - done = end - } - - return out.Bytes() -} - -// lines returns the lines in the file x, including newlines. -// If the file does not end in a newline, one is supplied -// along with a warning about the missing newline. -func lines(x []byte) []string { - l := strings.SplitAfter(string(x), "\n") - if l[len(l)-1] == "" { - l = l[:len(l)-1] - } else { - // Treat last line as having a message about the missing newline attached, - // using the same text as BSD/GNU diff (including the leading backslash). - l[len(l)-1] += "\n\\ No newline at end of file\n" - } - return l -} - -// tgs returns the pairs of indexes of the longest common subsequence -// of unique lines in x and y, where a unique line is one that appears -// once in x and once in y. -// -// The longest common subsequence algorithm is as described in -// Thomas G. Szymanski, “A Special Case of the Maximal Common -// Subsequence Problem,” Princeton TR #170 (January 1975), -// available at https://research.swtch.com/tgs170.pdf. -func tgs(x, y []string) []pair { - // Count the number of times each string appears in a and b. - // We only care about 0, 1, many, counted as 0, -1, -2 - // for the x side and 0, -4, -8 for the y side. - // Using negative numbers now lets us distinguish positive line numbers later. - m := make(map[string]int) - for _, s := range x { - if c := m[s]; c > -2 { - m[s] = c - 1 - } - } - for _, s := range y { - if c := m[s]; c > -8 { - m[s] = c - 4 - } - } - - // Now unique strings can be identified by m[s] = -1+-4. - // - // Gather the indexes of those strings in x and y, building: - // xi[i] = increasing indexes of unique strings in x. - // yi[i] = increasing indexes of unique strings in y. - // inv[i] = index j such that x[xi[i]] = y[yi[j]]. - var xi, yi, inv []int - for i, s := range y { - if m[s] == -1+-4 { - m[s] = len(yi) - yi = append(yi, i) - } - } - for i, s := range x { - if j, ok := m[s]; ok && j >= 0 { - xi = append(xi, i) - inv = append(inv, j) - } - } - - // Apply Algorithm A from Szymanski's paper. - // In those terms, A = J = inv and B = [0, n). - // We add sentinel pairs {0,0}, and {len(x),len(y)} - // to the returned sequence, to help the processing loop. - J := inv - n := len(xi) - T := make([]int, n) - L := make([]int, n) - for i := range T { - T[i] = n + 1 - } - for i := 0; i < n; i++ { - k := sort.Search(n, func(k int) bool { - return T[k] >= J[i] - }) - T[k] = J[i] - L[i] = k + 1 - } - k := 0 - for _, v := range L { - if k < v { - k = v - } - } - seq := make([]pair, 2+k) - seq[1+k] = pair{len(x), len(y)} // sentinel at end - lastj := n - for i := n - 1; i >= 0; i-- { - if L[i] == k && J[i] < lastj { - seq[k] = pair{xi[i], yi[J[i]]} - k-- - } - } - seq[0] = pair{0, 0} // sentinel at start - return seq -} diff --git a/testing/internal/diff/diff_test.go b/testing/internal/diff/diff_test.go deleted file mode 100644 index ff92512e..00000000 --- a/testing/internal/diff/diff_test.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2022 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 diff - -import ( - "bytes" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/txtar" - "path/filepath" - "testing" -) - -func clean(text []byte) []byte { - text = bytes.ReplaceAll(text, []byte("$\n"), []byte("\n")) - text = bytes.TrimSuffix(text, []byte("^D\n")) - return text -} - -func Test(t *testing.T) { - files, _ := filepath.Glob("testdata/*.txt") - if len(files) == 0 { - t.Fatalf("no testdata") - } - - for _, file := range files { - t.Run(filepath.Base(file), func(t *testing.T) { - a, err := txtar.ParseFile(file) - if err != nil { - t.Fatal(err) - } - if len(a.Files) != 3 || a.Files[2].Name != "diff" { - t.Fatalf("%s: want three files, third named \"diff\"", file) - } - diffs := Diff(a.Files[0].Name, clean(a.Files[0].Data), a.Files[1].Name, clean(a.Files[1].Data)) - want := clean(a.Files[2].Data) - if !bytes.Equal(diffs, want) { - t.Fatalf("%s: have:\n%s\nwant:\n%s\n%s", file, - diffs, want, Diff("have", diffs, "want", want)) - } - }) - } -} diff --git a/testing/internal/diff/testdata/allnew.txt b/testing/internal/diff/testdata/allnew.txt deleted file mode 100644 index 88756492..00000000 --- a/testing/internal/diff/testdata/allnew.txt +++ /dev/null @@ -1,13 +0,0 @@ --- old -- --- new -- -a -b -c --- diff -- -diff old new ---- old -+++ new -@@ -0,0 +1,3 @@ -+a -+b -+c diff --git a/testing/internal/diff/testdata/allold.txt b/testing/internal/diff/testdata/allold.txt deleted file mode 100644 index bcc9ac0e..00000000 --- a/testing/internal/diff/testdata/allold.txt +++ /dev/null @@ -1,13 +0,0 @@ --- old -- -a -b -c --- new -- --- diff -- -diff old new ---- old -+++ new -@@ -1,3 +0,0 @@ --a --b --c diff --git a/testing/internal/diff/testdata/basic.txt b/testing/internal/diff/testdata/basic.txt deleted file mode 100644 index d2565b5d..00000000 --- a/testing/internal/diff/testdata/basic.txt +++ /dev/null @@ -1,35 +0,0 @@ -Example from Hunt and McIlroy, “An Algorithm for Differential File Comparison.” -https://www.cs.dartmouth.edu/~doug/diff.pdf - --- old -- -a -b -c -d -e -f -g --- new -- -w -a -b -x -y -z -e --- diff -- -diff old new ---- old -+++ new -@@ -1,7 +1,7 @@ -+w - a - b --c --d -+x -+y -+z - e --f --g diff --git a/testing/internal/diff/testdata/dups.txt b/testing/internal/diff/testdata/dups.txt deleted file mode 100644 index d10524d0..00000000 --- a/testing/internal/diff/testdata/dups.txt +++ /dev/null @@ -1,40 +0,0 @@ --- old -- -a - -b - -c - -d - -e - -f --- new -- -a - -B - -C - -d - -e - -f --- diff -- -diff old new ---- old -+++ new -@@ -1,8 +1,8 @@ - a - $ --b -- --c -+B -+ -+C - $ - d - $ diff --git a/testing/internal/diff/testdata/end.txt b/testing/internal/diff/testdata/end.txt deleted file mode 100644 index 158637c1..00000000 --- a/testing/internal/diff/testdata/end.txt +++ /dev/null @@ -1,38 +0,0 @@ --- old -- -1 -2 -3 -4 -5 -6 -7 -eight -nine -ten -eleven --- new -- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 --- diff -- -diff old new ---- old -+++ new -@@ -5,7 +5,6 @@ - 5 - 6 - 7 --eight --nine --ten --eleven -+8 -+9 -+10 diff --git a/testing/internal/diff/testdata/eof.txt b/testing/internal/diff/testdata/eof.txt deleted file mode 100644 index 5dc145c4..00000000 --- a/testing/internal/diff/testdata/eof.txt +++ /dev/null @@ -1,9 +0,0 @@ --- old -- -a -b -c^D --- new -- -a -b -c^D --- diff -- diff --git a/testing/internal/diff/testdata/eof1.txt b/testing/internal/diff/testdata/eof1.txt deleted file mode 100644 index 1ebf621e..00000000 --- a/testing/internal/diff/testdata/eof1.txt +++ /dev/null @@ -1,18 +0,0 @@ --- old -- -a -b -c --- new -- -a -b -c^D --- diff -- -diff old new ---- old -+++ new -@@ -1,3 +1,3 @@ - a - b --c -+c -\ No newline at end of file diff --git a/testing/internal/diff/testdata/eof2.txt b/testing/internal/diff/testdata/eof2.txt deleted file mode 100644 index 047705e6..00000000 --- a/testing/internal/diff/testdata/eof2.txt +++ /dev/null @@ -1,18 +0,0 @@ --- old -- -a -b -c^D --- new -- -a -b -c --- diff -- -diff old new ---- old -+++ new -@@ -1,3 +1,3 @@ - a - b --c -\ No newline at end of file -+c diff --git a/testing/internal/diff/testdata/long.txt b/testing/internal/diff/testdata/long.txt deleted file mode 100644 index 3fc99f71..00000000 --- a/testing/internal/diff/testdata/long.txt +++ /dev/null @@ -1,62 +0,0 @@ --- old -- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -14½ -15 -16 -17 -18 -19 -20 --- new -- -1 -2 -3 -4 -5 -6 -8 -9 -10 -11 -12 -13 -14 -17 -18 -19 -20 --- diff -- -diff old new ---- old -+++ new -@@ -4,7 +4,6 @@ - 4 - 5 - 6 --7 - 8 - 9 - 10 -@@ -12,9 +11,6 @@ - 12 - 13 - 14 --14½ --15 --16 - 17 - 18 - 19 diff --git a/testing/internal/diff/testdata/same.txt b/testing/internal/diff/testdata/same.txt deleted file mode 100644 index 86b1100d..00000000 --- a/testing/internal/diff/testdata/same.txt +++ /dev/null @@ -1,5 +0,0 @@ --- old -- -hello world --- new -- -hello world --- diff -- diff --git a/testing/internal/diff/testdata/start.txt b/testing/internal/diff/testdata/start.txt deleted file mode 100644 index 217b2fdc..00000000 --- a/testing/internal/diff/testdata/start.txt +++ /dev/null @@ -1,34 +0,0 @@ --- old -- -e -pi -4 -5 -6 -7 -8 -9 -10 --- new -- -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 --- diff -- -diff old new ---- old -+++ new -@@ -1,5 +1,6 @@ --e --pi -+1 -+2 -+3 - 4 - 5 - 6 diff --git a/testing/internal/diff/testdata/triv.txt b/testing/internal/diff/testdata/triv.txt deleted file mode 100644 index ab5759fc..00000000 --- a/testing/internal/diff/testdata/triv.txt +++ /dev/null @@ -1,40 +0,0 @@ -Another example from Hunt and McIlroy, -“An Algorithm for Differential File Comparison.” -https://www.cs.dartmouth.edu/~doug/diff.pdf - -Anchored diff gives up on finding anything, -since there are no unique lines. - --- old -- -a -b -c -a -b -b -a --- new -- -c -a -b -a -b -c --- diff -- -diff old new ---- old -+++ new -@@ -1,7 +1,6 @@ --a --b --c --a --b --b --a -+c -+a -+b -+a -+b -+c diff --git a/testing/internal/fuzz/counters_supported.go b/testing/internal/fuzz/counters_supported.go deleted file mode 100644 index a8772391..00000000 --- a/testing/internal/fuzz/counters_supported.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 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 (darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64 || loong64) - -package fuzz - -import ( - "unsafe" -) - -// coverage returns a []byte containing unique 8-bit counters for each edge of -// the instrumented source code. This coverage data will only be generated if -// `-d=libfuzzer` is set at build time. This can be used to understand the code -// coverage of a test execution. -func coverage() []byte { - addr := unsafe.Pointer(&_counters) - size := uintptr(unsafe.Pointer(&_ecounters)) - uintptr(addr) - return unsafe.Slice((*byte)(addr), int(size)) -} diff --git a/testing/internal/fuzz/counters_unsupported.go b/testing/internal/fuzz/counters_unsupported.go deleted file mode 100644 index af2b56cd..00000000 --- a/testing/internal/fuzz/counters_unsupported.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2021 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. - -// TODO: expand the set of supported platforms, with testing. Nothing about -// the instrumentation is OS specific, but only amd64 and arm64 are -// supported in the runtime. See src/runtime/libfuzzer*. -// -// If you update this constraint, also update internal/platform.FuzzInstrumented. -// -//go:build !((darwin || linux || windows || freebsd || openbsd) && (amd64 || arm64 || loong64)) - -package fuzz - -// TODO(#48504): re-enable on platforms where instrumentation works. -// In theory, we shouldn't need this file at all: if the binary was built -// without coverage, then _counters and _ecounters should have the same address. -// However, this caused an init failure on aix/ppc64, so it's disabled here. - -// coverage returns a []byte containing unique 8-bit counters for each edge of -// the instrumented source code. This coverage data will only be generated if -// `-d=libfuzzer` is set at build time. This can be used to understand the code -// coverage of a test execution. -func coverage() []byte { return nil } diff --git a/testing/internal/fuzz/coverage.go b/testing/internal/fuzz/coverage.go deleted file mode 100644 index 8b39949b..00000000 --- a/testing/internal/fuzz/coverage.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "fmt" - "math/bits" -) - -// ResetCoverage sets all of the counters for each edge of the instrumented -// source code to 0. -func ResetCoverage() { - cov := coverage() - clear(cov) -} - -// SnapshotCoverage copies the current counter values into coverageSnapshot, -// preserving them for later inspection. SnapshotCoverage also rounds each -// counter down to the nearest power of two. This lets the coordinator store -// multiple values for each counter by OR'ing them together. -func SnapshotCoverage() { - cov := coverage() - for i, b := range cov { - coverageSnapshot[i] = pow2Table[b] - } -} - -// diffCoverage returns a set of bits set in snapshot but not in base. -// If there are no new bits set, diffCoverage returns nil. -func diffCoverage(base, snapshot []byte) []byte { - if len(base) != len(snapshot) { - panic(fmt.Sprintf("the number of coverage bits changed: before=%d, after=%d", len(base), len(snapshot))) - } - found := false - for i := range snapshot { - if snapshot[i]&^base[i] != 0 { - found = true - break - } - } - if !found { - return nil - } - diff := make([]byte, len(snapshot)) - for i := range diff { - diff[i] = snapshot[i] &^ base[i] - } - return diff -} - -// countNewCoverageBits returns the number of bits set in snapshot that are not -// set in base. -func countNewCoverageBits(base, snapshot []byte) int { - n := 0 - for i := range snapshot { - n += bits.OnesCount8(snapshot[i] &^ base[i]) - } - return n -} - -// isCoverageSubset returns true if all the base coverage bits are set in -// snapshot. -func isCoverageSubset(base, snapshot []byte) bool { - for i, v := range base { - if v&snapshot[i] != v { - return false - } - } - return true -} - -// hasCoverageBit returns true if snapshot has at least one bit set that is -// also set in base. -func hasCoverageBit(base, snapshot []byte) bool { - for i := range snapshot { - if snapshot[i]&base[i] != 0 { - return true - } - } - return false -} - -func countBits(cov []byte) int { - n := 0 - for _, c := range cov { - n += bits.OnesCount8(c) - } - return n -} - -var ( - coverageEnabled = len(coverage()) > 0 - coverageSnapshot = make([]byte, len(coverage())) - - // _counters and _ecounters mark the start and end, respectively, of where - // the 8-bit coverage counters reside in memory. They're known to cmd/link, - // which specially assigns their addresses for this purpose. - _counters, _ecounters [0]byte - - // lookup table for faster power of two rounding - pow2Table [256]byte -) - -func init() { - for i := range pow2Table { - b := byte(i) - b |= b >> 1 - b |= b >> 2 - b |= b >> 4 - b -= b >> 1 - pow2Table[i] = b - } -} diff --git a/testing/internal/fuzz/encoding.go b/testing/internal/fuzz/encoding.go deleted file mode 100644 index 270ef7a1..00000000 --- a/testing/internal/fuzz/encoding.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "bytes" - "fmt" - "go/ast" - "go/parser" - "go/token" - "math" - "strconv" - "strings" - "unicode/utf8" -) - -// encVersion1 will be the first line of a file with version 1 encoding. -var encVersion1 = "go test fuzz v1" - -// marshalCorpusFile encodes an arbitrary number of arguments into the file format for the -// corpus. -func marshalCorpusFile(vals ...any) []byte { - if len(vals) == 0 { - panic("must have at least one value to marshal") - } - b := bytes.NewBuffer([]byte(encVersion1 + "\n")) - // TODO(katiehockman): keep uint8 and int32 encoding where applicable, - // instead of changing to byte and rune respectively. - for _, val := range vals { - switch t := val.(type) { - case int, int8, int16, int64, uint, uint16, uint32, uint64, bool: - fmt.Fprintf(b, "%T(%v)\n", t, t) - case float32: - if math.IsNaN(float64(t)) && math.Float32bits(t) != math.Float32bits(float32(math.NaN())) { - // We encode unusual NaNs as hex values, because that is how users are - // likely to encounter them in literature about floating-point encoding. - // This allows us to reproduce fuzz failures that depend on the specific - // NaN representation (for float32 there are about 2^24 possibilities!), - // not just the fact that the value is *a* NaN. - // - // Note that the specific value of float32(math.NaN()) can vary based on - // whether the architecture represents signaling NaNs using a low bit - // (as is common) or a high bit (as commonly implemented on MIPS - // hardware before around 2012). We believe that the increase in clarity - // from identifying "NaN" with math.NaN() is worth the slight ambiguity - // from a platform-dependent value. - fmt.Fprintf(b, "math.Float32frombits(0x%x)\n", math.Float32bits(t)) - } else { - // We encode all other values — including the NaN value that is - // bitwise-identical to float32(math.Nan()) — using the default - // formatting, which is equivalent to strconv.FormatFloat with format - // 'g' and can be parsed by strconv.ParseFloat. - // - // For an ordinary floating-point number this format includes - // sufficiently many digits to reconstruct the exact value. For positive - // or negative infinity it is the string "+Inf" or "-Inf". For positive - // or negative zero it is "0" or "-0". For NaN, it is the string "NaN". - fmt.Fprintf(b, "%T(%v)\n", t, t) - } - case float64: - if math.IsNaN(t) && math.Float64bits(t) != math.Float64bits(math.NaN()) { - fmt.Fprintf(b, "math.Float64frombits(0x%x)\n", math.Float64bits(t)) - } else { - fmt.Fprintf(b, "%T(%v)\n", t, t) - } - case string: - fmt.Fprintf(b, "string(%q)\n", t) - case rune: // int32 - // Although rune and int32 are represented by the same type, only a subset - // of valid int32 values can be expressed as rune literals. Notably, - // negative numbers, surrogate halves, and values above unicode.MaxRune - // have no quoted representation. - // - // fmt with "%q" (and the corresponding functions in the strconv package) - // would quote out-of-range values to the Unicode replacement character - // instead of the original value (see https://go.dev/issue/51526), so - // they must be treated as int32 instead. - // - // We arbitrarily draw the line at UTF-8 validity, which biases toward the - // "rune" interpretation. (However, we accept either format as input.) - if utf8.ValidRune(t) { - fmt.Fprintf(b, "rune(%q)\n", t) - } else { - fmt.Fprintf(b, "int32(%v)\n", t) - } - case byte: // uint8 - // For bytes, we arbitrarily prefer the character interpretation. - // (Every byte has a valid character encoding.) - fmt.Fprintf(b, "byte(%q)\n", t) - case []byte: // []uint8 - fmt.Fprintf(b, "[]byte(%q)\n", t) - default: - panic(fmt.Sprintf("unsupported type: %T", t)) - } - } - return b.Bytes() -} - -// unmarshalCorpusFile decodes corpus bytes into their respective values. -func unmarshalCorpusFile(b []byte) ([]any, error) { - if len(b) == 0 { - return nil, fmt.Errorf("cannot unmarshal empty string") - } - lines := bytes.Split(b, []byte("\n")) - if len(lines) < 2 { - return nil, fmt.Errorf("must include version and at least one value") - } - version := strings.TrimSuffix(string(lines[0]), "\r") - if version != encVersion1 { - return nil, fmt.Errorf("unknown encoding version: %s", version) - } - var vals []any - for _, line := range lines[1:] { - line = bytes.TrimSpace(line) - if len(line) == 0 { - continue - } - v, err := parseCorpusValue(line) - if err != nil { - return nil, fmt.Errorf("malformed line %q: %v", line, err) - } - vals = append(vals, v) - } - return vals, nil -} - -func parseCorpusValue(line []byte) (any, error) { - fs := token.NewFileSet() - expr, err := parser.ParseExprFrom(fs, "(test)", line, 0) - if err != nil { - return nil, err - } - call, ok := expr.(*ast.CallExpr) - if !ok { - return nil, fmt.Errorf("expected call expression") - } - if len(call.Args) != 1 { - return nil, fmt.Errorf("expected call expression with 1 argument; got %d", len(call.Args)) - } - arg := call.Args[0] - - if arrayType, ok := call.Fun.(*ast.ArrayType); ok { - if arrayType.Len != nil { - return nil, fmt.Errorf("expected []byte or primitive type") - } - elt, ok := arrayType.Elt.(*ast.Ident) - if !ok || elt.Name != "byte" { - return nil, fmt.Errorf("expected []byte") - } - lit, ok := arg.(*ast.BasicLit) - if !ok || lit.Kind != token.STRING { - return nil, fmt.Errorf("string literal required for type []byte") - } - s, err := strconv.Unquote(lit.Value) - if err != nil { - return nil, err - } - return []byte(s), nil - } - - var idType *ast.Ident - if selector, ok := call.Fun.(*ast.SelectorExpr); ok { - xIdent, ok := selector.X.(*ast.Ident) - if !ok || xIdent.Name != "math" { - return nil, fmt.Errorf("invalid selector type") - } - switch selector.Sel.Name { - case "Float64frombits": - idType = &ast.Ident{Name: "float64-bits"} - case "Float32frombits": - idType = &ast.Ident{Name: "float32-bits"} - default: - return nil, fmt.Errorf("invalid selector type") - } - } else { - idType, ok = call.Fun.(*ast.Ident) - if !ok { - return nil, fmt.Errorf("expected []byte or primitive type") - } - if idType.Name == "bool" { - id, ok := arg.(*ast.Ident) - if !ok { - return nil, fmt.Errorf("malformed bool") - } - if id.Name == "true" { - return true, nil - } else if id.Name == "false" { - return false, nil - } else { - return nil, fmt.Errorf("true or false required for type bool") - } - } - } - - var ( - val string - kind token.Token - ) - if op, ok := arg.(*ast.UnaryExpr); ok { - switch lit := op.X.(type) { - case *ast.BasicLit: - if op.Op != token.SUB { - return nil, fmt.Errorf("unsupported operation on int/float: %v", op.Op) - } - // Special case for negative numbers. - val = op.Op.String() + lit.Value // e.g. "-" + "124" - kind = lit.Kind - case *ast.Ident: - if lit.Name != "Inf" { - return nil, fmt.Errorf("expected operation on int or float type") - } - if op.Op == token.SUB { - val = "-Inf" - } else { - val = "+Inf" - } - kind = token.FLOAT - default: - return nil, fmt.Errorf("expected operation on int or float type") - } - } else { - switch lit := arg.(type) { - case *ast.BasicLit: - val, kind = lit.Value, lit.Kind - case *ast.Ident: - if lit.Name != "NaN" { - return nil, fmt.Errorf("literal value required for primitive type") - } - val, kind = "NaN", token.FLOAT - default: - return nil, fmt.Errorf("literal value required for primitive type") - } - } - - switch typ := idType.Name; typ { - case "string": - if kind != token.STRING { - return nil, fmt.Errorf("string literal value required for type string") - } - return strconv.Unquote(val) - case "byte", "rune": - if kind == token.INT { - switch typ { - case "rune": - return parseInt(val, typ) - case "byte": - return parseUint(val, typ) - } - } - if kind != token.CHAR { - return nil, fmt.Errorf("character literal required for byte/rune types") - } - n := len(val) - if n < 2 { - return nil, fmt.Errorf("malformed character literal, missing single quotes") - } - code, _, _, err := strconv.UnquoteChar(val[1:n-1], '\'') - if err != nil { - return nil, err - } - if typ == "rune" { - return code, nil - } - if code >= 256 { - return nil, fmt.Errorf("can only encode single byte to a byte type") - } - return byte(code), nil - case "int", "int8", "int16", "int32", "int64": - if kind != token.INT { - return nil, fmt.Errorf("integer literal required for int types") - } - return parseInt(val, typ) - case "uint", "uint8", "uint16", "uint32", "uint64": - if kind != token.INT { - return nil, fmt.Errorf("integer literal required for uint types") - } - return parseUint(val, typ) - case "float32": - if kind != token.FLOAT && kind != token.INT { - return nil, fmt.Errorf("float or integer literal required for float32 type") - } - v, err := strconv.ParseFloat(val, 32) - return float32(v), err - case "float64": - if kind != token.FLOAT && kind != token.INT { - return nil, fmt.Errorf("float or integer literal required for float64 type") - } - return strconv.ParseFloat(val, 64) - case "float32-bits": - if kind != token.INT { - return nil, fmt.Errorf("integer literal required for math.Float32frombits type") - } - bits, err := parseUint(val, "uint32") - if err != nil { - return nil, err - } - return math.Float32frombits(bits.(uint32)), nil - case "float64-bits": - if kind != token.FLOAT && kind != token.INT { - return nil, fmt.Errorf("integer literal required for math.Float64frombits type") - } - bits, err := parseUint(val, "uint64") - if err != nil { - return nil, err - } - return math.Float64frombits(bits.(uint64)), nil - default: - return nil, fmt.Errorf("expected []byte or primitive type") - } -} - -// parseInt returns an integer of value val and type typ. -func parseInt(val, typ string) (any, error) { - switch typ { - case "int": - // The int type may be either 32 or 64 bits. If 32, the fuzz tests in the - // corpus may include 64-bit values produced by fuzzing runs on 64-bit - // architectures. When running those tests, we implicitly wrap the values to - // fit in a regular int. (The test case is still “interesting”, even if the - // specific values of its inputs are platform-dependent.) - i, err := strconv.ParseInt(val, 0, 64) - return int(i), err - case "int8": - i, err := strconv.ParseInt(val, 0, 8) - return int8(i), err - case "int16": - i, err := strconv.ParseInt(val, 0, 16) - return int16(i), err - case "int32", "rune": - i, err := strconv.ParseInt(val, 0, 32) - return int32(i), err - case "int64": - return strconv.ParseInt(val, 0, 64) - default: - panic("unreachable") - } -} - -// parseUint returns an unsigned integer of value val and type typ. -func parseUint(val, typ string) (any, error) { - switch typ { - case "uint": - i, err := strconv.ParseUint(val, 0, 64) - return uint(i), err - case "uint8", "byte": - i, err := strconv.ParseUint(val, 0, 8) - return uint8(i), err - case "uint16": - i, err := strconv.ParseUint(val, 0, 16) - return uint16(i), err - case "uint32": - i, err := strconv.ParseUint(val, 0, 32) - return uint32(i), err - case "uint64": - return strconv.ParseUint(val, 0, 64) - default: - panic("unreachable") - } -} diff --git a/testing/internal/fuzz/encoding_test.go b/testing/internal/fuzz/encoding_test.go deleted file mode 100644 index 29717942..00000000 --- a/testing/internal/fuzz/encoding_test.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "math" - "strconv" - "testing" - "unicode" -) - -func TestUnmarshalMarshal(t *testing.T) { - var tests = []struct { - desc string - in string - reject bool - want string // if different from in - }{ - { - desc: "missing version", - in: "int(1234)", - reject: true, - }, - { - desc: "malformed string", - in: `go test fuzz v1 -string("a"bcad")`, - reject: true, - }, - { - desc: "empty value", - in: `go test fuzz v1 -int()`, - reject: true, - }, - { - desc: "negative uint", - in: `go test fuzz v1 -uint(-32)`, - reject: true, - }, - { - desc: "int8 too large", - in: `go test fuzz v1 -int8(1234456)`, - reject: true, - }, - { - desc: "multiplication in int value", - in: `go test fuzz v1 -int(20*5)`, - reject: true, - }, - { - desc: "double negation", - in: `go test fuzz v1 -int(--5)`, - reject: true, - }, - { - desc: "malformed bool", - in: `go test fuzz v1 -bool(0)`, - reject: true, - }, - { - desc: "malformed byte", - in: `go test fuzz v1 -byte('aa)`, - reject: true, - }, - { - desc: "byte out of range", - in: `go test fuzz v1 -byte('☃')`, - reject: true, - }, - { - desc: "extra newline", - in: `go test fuzz v1 -string("has extra newline") -`, - want: `go test fuzz v1 -string("has extra newline")`, - }, - { - desc: "trailing spaces", - in: `go test fuzz v1 -string("extra") -[]byte("spacing") - `, - want: `go test fuzz v1 -string("extra") -[]byte("spacing")`, - }, - { - desc: "float types", - in: `go test fuzz v1 -float64(0) -float32(0)`, - }, - { - desc: "various types", - in: `go test fuzz v1 -int(-23) -int8(-2) -int64(2342425) -uint(1) -uint16(234) -uint32(352342) -uint64(123) -rune('œ') -byte('K') -byte('ÿ') -[]byte("hello¿") -[]byte("a") -bool(true) -string("hello\\xbd\\xb2=\\xbc ⌘") -float64(-12.5) -float32(2.5)`, - }, - { - desc: "float edge cases", - // The two IEEE 754 bit patterns used for the math.Float{64,32}frombits - // encodings are non-math.NAN quiet-NaN values. Since they are not equal - // to math.NaN(), they should be re-encoded to their bit patterns. They - // are, respectively: - // * math.Float64bits(math.NaN())+1 - // * math.Float32bits(float32(math.NaN()))+1 - in: `go test fuzz v1 -float32(-0) -float64(-0) -float32(+Inf) -float32(-Inf) -float32(NaN) -float64(+Inf) -float64(-Inf) -float64(NaN) -math.Float64frombits(0x7ff8000000000002) -math.Float32frombits(0x7fc00001)`, - }, - { - desc: "int variations", - // Although we arbitrarily choose default integer bases (0 or 16), we may - // want to change those arbitrary choices in the future and should not - // break the parser. Verify that integers in the opposite bases still - // parse correctly. - in: `go test fuzz v1 -int(0x0) -int32(0x41) -int64(0xfffffffff) -uint32(0xcafef00d) -uint64(0xffffffffffffffff) -uint8(0b0000000) -byte(0x0) -byte('\000') -byte('\u0000') -byte('\'') -math.Float64frombits(9221120237041090562) -math.Float32frombits(2143289345)`, - want: `go test fuzz v1 -int(0) -rune('A') -int64(68719476735) -uint32(3405705229) -uint64(18446744073709551615) -byte('\x00') -byte('\x00') -byte('\x00') -byte('\x00') -byte('\'') -math.Float64frombits(0x7ff8000000000002) -math.Float32frombits(0x7fc00001)`, - }, - { - desc: "rune validation", - in: `go test fuzz v1 -rune(0) -rune(0x41) -rune(-1) -rune(0xfffd) -rune(0xd800) -rune(0x10ffff) -rune(0x110000) -`, - want: `go test fuzz v1 -rune('\x00') -rune('A') -int32(-1) -rune('�') -int32(55296) -rune('\U0010ffff') -int32(1114112)`, - }, - { - desc: "int overflow", - in: `go test fuzz v1 -int(0x7fffffffffffffff) -uint(0xffffffffffffffff)`, - want: func() string { - switch strconv.IntSize { - case 32: - return `go test fuzz v1 -int(-1) -uint(4294967295)` - case 64: - return `go test fuzz v1 -int(9223372036854775807) -uint(18446744073709551615)` - default: - panic("unreachable") - } - }(), - }, - { - desc: "windows new line", - in: "go test fuzz v1\r\nint(0)\r\n", - want: "go test fuzz v1\nint(0)", - }, - } - for _, test := range tests { - t.Run(test.desc, func(t *testing.T) { - vals, err := unmarshalCorpusFile([]byte(test.in)) - if test.reject { - if err == nil { - t.Fatalf("unmarshal unexpected success") - } - return - } - if err != nil { - t.Fatalf("unmarshal unexpected error: %v", err) - } - newB := marshalCorpusFile(vals...) - if newB[len(newB)-1] != '\n' { - t.Error("didn't write final newline to corpus file") - } - - want := test.want - if want == "" { - want = test.in - } - want += "\n" - got := string(newB) - if got != want { - t.Errorf("unexpected marshaled value\ngot:\n%s\nwant:\n%s", got, want) - } - }) - } -} - -// BenchmarkMarshalCorpusFile measures the time it takes to serialize byte -// slices of various sizes to a corpus file. The slice contains a repeating -// sequence of bytes 0-255 to mix escaped and non-escaped characters. -func BenchmarkMarshalCorpusFile(b *testing.B) { - buf := make([]byte, 1024*1024) - for i := 0; i < len(buf); i++ { - buf[i] = byte(i) - } - - for sz := 1; sz <= len(buf); sz <<= 1 { - sz := sz - b.Run(strconv.Itoa(sz), func(b *testing.B) { - for i := 0; i < b.N; i++ { - b.SetBytes(int64(sz)) - marshalCorpusFile(buf[:sz]) - } - }) - } -} - -// BenchmarkUnmarshalCorpusfile measures the time it takes to deserialize -// files encoding byte slices of various sizes. The slice contains a repeating -// sequence of bytes 0-255 to mix escaped and non-escaped characters. -func BenchmarkUnmarshalCorpusFile(b *testing.B) { - buf := make([]byte, 1024*1024) - for i := 0; i < len(buf); i++ { - buf[i] = byte(i) - } - - for sz := 1; sz <= len(buf); sz <<= 1 { - sz := sz - data := marshalCorpusFile(buf[:sz]) - b.Run(strconv.Itoa(sz), func(b *testing.B) { - for i := 0; i < b.N; i++ { - b.SetBytes(int64(sz)) - unmarshalCorpusFile(data) - } - }) - } -} - -func TestByteRoundTrip(t *testing.T) { - for x := 0; x < 256; x++ { - b1 := byte(x) - buf := marshalCorpusFile(b1) - vs, err := unmarshalCorpusFile(buf) - if err != nil { - t.Fatal(err) - } - b2 := vs[0].(byte) - if b2 != b1 { - t.Fatalf("unmarshaled %v, want %v:\n%s", b2, b1, buf) - } - } -} - -func TestInt8RoundTrip(t *testing.T) { - for x := -128; x < 128; x++ { - i1 := int8(x) - buf := marshalCorpusFile(i1) - vs, err := unmarshalCorpusFile(buf) - if err != nil { - t.Fatal(err) - } - i2 := vs[0].(int8) - if i2 != i1 { - t.Fatalf("unmarshaled %v, want %v:\n%s", i2, i1, buf) - } - } -} - -func FuzzFloat64RoundTrip(f *testing.F) { - f.Add(math.Float64bits(0)) - f.Add(math.Float64bits(math.Copysign(0, -1))) - f.Add(math.Float64bits(math.MaxFloat64)) - f.Add(math.Float64bits(math.SmallestNonzeroFloat64)) - f.Add(math.Float64bits(math.NaN())) - f.Add(uint64(0x7FF0000000000001)) // signaling NaN - f.Add(math.Float64bits(math.Inf(1))) - f.Add(math.Float64bits(math.Inf(-1))) - - f.Fuzz(func(t *testing.T, u1 uint64) { - x1 := math.Float64frombits(u1) - - b := marshalCorpusFile(x1) - t.Logf("marshaled math.Float64frombits(0x%x):\n%s", u1, b) - - xs, err := unmarshalCorpusFile(b) - if err != nil { - t.Fatal(err) - } - if len(xs) != 1 { - t.Fatalf("unmarshaled %d values", len(xs)) - } - x2 := xs[0].(float64) - u2 := math.Float64bits(x2) - if u2 != u1 { - t.Errorf("unmarshaled %v (bits 0x%x)", x2, u2) - } - }) -} - -func FuzzRuneRoundTrip(f *testing.F) { - f.Add(rune(-1)) - f.Add(rune(0xd800)) - f.Add(rune(0xdfff)) - f.Add(rune(unicode.ReplacementChar)) - f.Add(rune(unicode.MaxASCII)) - f.Add(rune(unicode.MaxLatin1)) - f.Add(rune(unicode.MaxRune)) - f.Add(rune(unicode.MaxRune + 1)) - f.Add(rune(-0x80000000)) - f.Add(rune(0x7fffffff)) - - f.Fuzz(func(t *testing.T, r1 rune) { - b := marshalCorpusFile(r1) - t.Logf("marshaled rune(0x%x):\n%s", r1, b) - - rs, err := unmarshalCorpusFile(b) - if err != nil { - t.Fatal(err) - } - if len(rs) != 1 { - t.Fatalf("unmarshaled %d values", len(rs)) - } - r2 := rs[0].(rune) - if r2 != r1 { - t.Errorf("unmarshaled rune(0x%x)", r2) - } - }) -} - -func FuzzStringRoundTrip(f *testing.F) { - f.Add("") - f.Add("\x00") - f.Add(string([]rune{unicode.ReplacementChar})) - - f.Fuzz(func(t *testing.T, s1 string) { - b := marshalCorpusFile(s1) - t.Logf("marshaled %q:\n%s", s1, b) - - rs, err := unmarshalCorpusFile(b) - if err != nil { - t.Fatal(err) - } - if len(rs) != 1 { - t.Fatalf("unmarshaled %d values", len(rs)) - } - s2 := rs[0].(string) - if s2 != s1 { - t.Errorf("unmarshaled %q", s2) - } - }) -} diff --git a/testing/internal/fuzz/fuzz.go b/testing/internal/fuzz/fuzz.go deleted file mode 100644 index 398e9f34..00000000 --- a/testing/internal/fuzz/fuzz.go +++ /dev/null @@ -1,1102 +0,0 @@ -// 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 fuzz provides common fuzzing functionality for tests built with -// "go test" and for programs that use fuzzing functionality in the testing -// package. -package fuzz - -import ( - "bytes" - "context" - "crypto/sha256" - "errors" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebug" - "io" - "math/bits" - "os" - "path/filepath" - "reflect" - "runtime" - "strings" - "time" -) - -// CoordinateFuzzingOpts is a set of arguments for CoordinateFuzzing. -// The zero value is valid for each field unless specified otherwise. -type CoordinateFuzzingOpts struct { - // Log is a writer for logging progress messages and warnings. - // If nil, io.Discard will be used instead. - Log io.Writer - - // Timeout is the amount of wall clock time to spend fuzzing after the corpus - // has loaded. If zero, there will be no time limit. - Timeout time.Duration - - // Limit is the number of random values to generate and test. If zero, - // there will be no limit on the number of generated values. - Limit int64 - - // MinimizeTimeout is the amount of wall clock time to spend minimizing - // after discovering a crasher. If zero, there will be no time limit. If - // MinimizeTimeout and MinimizeLimit are both zero, then minimization will - // be disabled. - MinimizeTimeout time.Duration - - // MinimizeLimit is the maximum number of calls to the fuzz function to be - // made while minimizing after finding a crash. If zero, there will be no - // limit. Calls to the fuzz function made when minimizing also count toward - // Limit. If MinimizeTimeout and MinimizeLimit are both zero, then - // minimization will be disabled. - MinimizeLimit int64 - - // parallel is the number of worker processes to run in parallel. If zero, - // CoordinateFuzzing will run GOMAXPROCS workers. - Parallel int - - // Seed is a list of seed values added by the fuzz target with testing.F.Add - // and in testdata. - Seed []CorpusEntry - - // Types is the list of types which make up a corpus entry. - // Types must be set and must match values in Seed. - Types []reflect.Type - - // CorpusDir is a directory where files containing values that crash the - // code being tested may be written. CorpusDir must be set. - CorpusDir string - - // CacheDir is a directory containing additional "interesting" values. - // The fuzzer may derive new values from these, and may write new values here. - CacheDir string -} - -// CoordinateFuzzing creates several worker processes and communicates with -// them to test random inputs that could trigger crashes and expose bugs. -// The worker processes run the same binary in the same directory with the -// same environment variables as the coordinator process. Workers also run -// with the same arguments as the coordinator, except with the -test.fuzzworker -// flag prepended to the argument list. -// -// If a crash occurs, the function will return an error containing information -// about the crash, which can be reported to the user. -func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err error) { - if err := ctx.Err(); err != nil { - return err - } - if opts.Log == nil { - opts.Log = io.Discard - } - if opts.Parallel == 0 { - opts.Parallel = runtime.GOMAXPROCS(0) - } - if opts.Limit > 0 && int64(opts.Parallel) > opts.Limit { - // Don't start more workers than we need. - opts.Parallel = int(opts.Limit) - } - - c, err := newCoordinator(opts) - if err != nil { - return err - } - - if opts.Timeout > 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, opts.Timeout) - defer cancel() - } - - // fuzzCtx is used to stop workers, for example, after finding a crasher. - fuzzCtx, cancelWorkers := context.WithCancel(ctx) - defer cancelWorkers() - doneC := ctx.Done() - - // stop is called when a worker encounters a fatal error. - var fuzzErr error - stopping := false - stop := func(err error) { - if shouldPrintDebugInfo() { - _, file, line, ok := runtime.Caller(1) - if ok { - c.debugLogf("stop called at %s:%d. stopping: %t", file, line, stopping) - } else { - c.debugLogf("stop called at unknown. stopping: %t", stopping) - } - } - - if err == fuzzCtx.Err() || isInterruptError(err) { - // Suppress cancellation errors and terminations due to SIGINT. - // The messages are not helpful since either the user triggered the error - // (with ^C) or another more helpful message will be printed (a crasher). - err = nil - } - if err != nil && (fuzzErr == nil || fuzzErr == ctx.Err()) { - fuzzErr = err - } - if stopping { - return - } - stopping = true - cancelWorkers() - doneC = nil - } - - // Ensure that any crash we find is written to the corpus, even if an error - // or interruption occurs while minimizing it. - crashWritten := false - defer func() { - if c.crashMinimizing == nil || crashWritten { - return - } - werr := writeToCorpus(&c.crashMinimizing.entry, opts.CorpusDir) - if werr != nil { - err = fmt.Errorf("%w\n%v", err, werr) - return - } - if err == nil { - err = &crashError{ - path: c.crashMinimizing.entry.Path, - err: errors.New(c.crashMinimizing.crasherMsg), - } - } - }() - - // Start workers. - // TODO(jayconrod): do we want to support fuzzing different binaries? - dir := "" // same as self - binPath := os.Args[0] - args := append([]string{"-test.fuzzworker"}, os.Args[1:]...) - env := os.Environ() // same as self - - errC := make(chan error) - workers := make([]*worker, opts.Parallel) - for i := range workers { - var err error - workers[i], err = newWorker(c, dir, binPath, args, env) - if err != nil { - return err - } - } - for i := range workers { - w := workers[i] - go func() { - err := w.coordinate(fuzzCtx) - if fuzzCtx.Err() != nil || isInterruptError(err) { - err = nil - } - cleanErr := w.cleanup() - if err == nil { - err = cleanErr - } - errC <- err - }() - } - - // Main event loop. - // Do not return until all workers have terminated. We avoid a deadlock by - // receiving messages from workers even after ctx is canceled. - activeWorkers := len(workers) - statTicker := time.NewTicker(3 * time.Second) - defer statTicker.Stop() - defer c.logStats() - - c.logStats() - for { - // If there is an execution limit, and we've reached it, stop. - if c.opts.Limit > 0 && c.count >= c.opts.Limit { - stop(nil) - } - - var inputC chan fuzzInput - input, ok := c.peekInput() - if ok && c.crashMinimizing == nil && !stopping { - inputC = c.inputC - } - - var minimizeC chan fuzzMinimizeInput - minimizeInput, ok := c.peekMinimizeInput() - if ok && !stopping { - minimizeC = c.minimizeC - } - - select { - case <-doneC: - // Interrupted, canceled, or timed out. - // stop sets doneC to nil, so we don't busy wait here. - stop(ctx.Err()) - - case err := <-errC: - // A worker terminated, possibly after encountering a fatal error. - stop(err) - activeWorkers-- - if activeWorkers == 0 { - return fuzzErr - } - - case result := <-c.resultC: - // Received response from worker. - if stopping { - break - } - c.updateStats(result) - - if result.crasherMsg != "" { - if c.warmupRun() && result.entry.IsSeed { - target := filepath.Base(c.opts.CorpusDir) - fmt.Fprintf(c.opts.Log, "failure while testing seed corpus entry: %s/%s\n", target, testName(result.entry.Parent)) - stop(errors.New(result.crasherMsg)) - break - } - if c.canMinimize() && result.canMinimize { - if c.crashMinimizing != nil { - // This crash is not minimized, and another crash is being minimized. - // Ignore this one and wait for the other one to finish. - if shouldPrintDebugInfo() { - c.debugLogf("found unminimized crasher, skipping in favor of minimizable crasher") - } - break - } - // Found a crasher but haven't yet attempted to minimize it. - // Send it back to a worker for minimization. Disable inputC so - // other workers don't continue fuzzing. - c.crashMinimizing = &result - fmt.Fprintf(c.opts.Log, "fuzz: minimizing %d-byte failing input file\n", len(result.entry.Data)) - c.queueForMinimization(result, nil) - } else if !crashWritten { - // Found a crasher that's either minimized or not minimizable. - // Write to corpus and stop. - err := writeToCorpus(&result.entry, opts.CorpusDir) - if err == nil { - crashWritten = true - err = &crashError{ - path: result.entry.Path, - err: errors.New(result.crasherMsg), - } - } - if shouldPrintDebugInfo() { - c.debugLogf( - "found crasher, id: %s, parent: %s, gen: %d, size: %d, exec time: %s", - result.entry.Path, - result.entry.Parent, - result.entry.Generation, - len(result.entry.Data), - result.entryDuration, - ) - } - stop(err) - } - } else if result.coverageData != nil { - if c.warmupRun() { - if shouldPrintDebugInfo() { - c.debugLogf( - "processed an initial input, id: %s, new bits: %d, size: %d, exec time: %s", - result.entry.Parent, - countBits(diffCoverage(c.coverageMask, result.coverageData)), - len(result.entry.Data), - result.entryDuration, - ) - } - c.updateCoverage(result.coverageData) - c.warmupInputLeft-- - if c.warmupInputLeft == 0 { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, gathering baseline coverage: %d/%d completed, now fuzzing with %d workers\n", c.elapsed(), c.warmupInputCount, c.warmupInputCount, c.opts.Parallel) - if shouldPrintDebugInfo() { - c.debugLogf( - "finished processing input corpus, entries: %d, initial coverage bits: %d", - len(c.corpus.entries), - countBits(c.coverageMask), - ) - } - } - } else if keepCoverage := diffCoverage(c.coverageMask, result.coverageData); keepCoverage != nil { - // Found a value that expanded coverage. - // It's not a crasher, but we may want to add it to the on-disk - // corpus and prioritize it for future fuzzing. - // TODO(jayconrod, katiehockman): Prioritize fuzzing these - // values which expanded coverage, perhaps based on the - // number of new edges that this result expanded. - // TODO(jayconrod, katiehockman): Don't write a value that's already - // in the corpus. - if c.canMinimize() && result.canMinimize && c.crashMinimizing == nil { - // Send back to workers to find a smaller value that preserves - // at least one new coverage bit. - c.queueForMinimization(result, keepCoverage) - } else { - // Update the coordinator's coverage mask and save the value. - inputSize := len(result.entry.Data) - entryNew, err := c.addCorpusEntries(true, result.entry) - if err != nil { - stop(err) - break - } - if !entryNew { - if shouldPrintDebugInfo() { - c.debugLogf( - "ignoring duplicate input which increased coverage, id: %s", - result.entry.Path, - ) - } - break - } - c.updateCoverage(keepCoverage) - c.inputQueue.enqueue(result.entry) - c.interestingCount++ - if shouldPrintDebugInfo() { - c.debugLogf( - "new interesting input, id: %s, parent: %s, gen: %d, new bits: %d, total bits: %d, size: %d, exec time: %s", - result.entry.Path, - result.entry.Parent, - result.entry.Generation, - countBits(keepCoverage), - countBits(c.coverageMask), - inputSize, - result.entryDuration, - ) - } - } - } else { - if shouldPrintDebugInfo() { - c.debugLogf( - "worker reported interesting input that doesn't expand coverage, id: %s, parent: %s, canMinimize: %t", - result.entry.Path, - result.entry.Parent, - result.canMinimize, - ) - } - } - } else if c.warmupRun() { - // No error or coverage data was reported for this input during - // warmup, so continue processing results. - c.warmupInputLeft-- - if c.warmupInputLeft == 0 { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, testing seed corpus: %d/%d completed, now fuzzing with %d workers\n", c.elapsed(), c.warmupInputCount, c.warmupInputCount, c.opts.Parallel) - if shouldPrintDebugInfo() { - c.debugLogf( - "finished testing-only phase, entries: %d", - len(c.corpus.entries), - ) - } - } - } - - case inputC <- input: - // Sent the next input to a worker. - c.sentInput(input) - - case minimizeC <- minimizeInput: - // Sent the next input for minimization to a worker. - c.sentMinimizeInput(minimizeInput) - - case <-statTicker.C: - c.logStats() - } - } - - // TODO(jayconrod,katiehockman): if a crasher can't be written to the corpus, - // write to the cache instead. -} - -// crashError wraps a crasher written to the seed corpus. It saves the name -// of the file where the input causing the crasher was saved. The testing -// framework uses this to report a command to re-run that specific input. -type crashError struct { - path string - err error -} - -func (e *crashError) Error() string { - return e.err.Error() -} - -func (e *crashError) Unwrap() error { - return e.err -} - -func (e *crashError) CrashPath() string { - return e.path -} - -type corpus struct { - entries []CorpusEntry - hashes map[[sha256.Size]byte]bool -} - -// addCorpusEntries adds entries to the corpus, and optionally writes the entries -// to the cache directory. If an entry is already in the corpus it is skipped. If -// all of the entries are unique, addCorpusEntries returns true and a nil error, -// if at least one of the entries was a duplicate, it returns false and a nil error. -func (c *coordinator) addCorpusEntries(addToCache bool, entries ...CorpusEntry) (bool, error) { - noDupes := true - for _, e := range entries { - data, err := corpusEntryData(e) - if err != nil { - return false, err - } - h := sha256.Sum256(data) - if c.corpus.hashes[h] { - noDupes = false - continue - } - if addToCache { - if err := writeToCorpus(&e, c.opts.CacheDir); err != nil { - return false, err - } - // For entries written to disk, we don't hold onto the bytes, - // since the corpus would consume a significant amount of - // memory. - e.Data = nil - } - c.corpus.hashes[h] = true - c.corpus.entries = append(c.corpus.entries, e) - } - return noDupes, nil -} - -// CorpusEntry represents an individual input for fuzzing. -// -// We must use an equivalent type in the testing and testing/internal/testdeps -// packages, but testing can't import this package directly, and we don't want -// to export this type from testing. Instead, we use the same struct type and -// use a type alias (not a defined type) for convenience. -type CorpusEntry = struct { - Parent string - - // Path is the path of the corpus file, if the entry was loaded from disk. - // For other entries, including seed values provided by f.Add, Path is the - // name of the test, e.g. seed#0 or its hash. - Path string - - // Data is the raw input data. Data should only be populated for seed - // values. For on-disk corpus files, Data will be nil, as it will be loaded - // from disk using Path. - Data []byte - - // Values is the unmarshaled values from a corpus file. - Values []any - - Generation int - - // IsSeed indicates whether this entry is part of the seed corpus. - IsSeed bool -} - -// corpusEntryData returns the raw input bytes, either from the data struct -// field, or from disk. -func corpusEntryData(ce CorpusEntry) ([]byte, error) { - if ce.Data != nil { - return ce.Data, nil - } - - return os.ReadFile(ce.Path) -} - -type fuzzInput struct { - // entry is the value to test initially. The worker will randomly mutate - // values from this starting point. - entry CorpusEntry - - // timeout is the time to spend fuzzing variations of this input, - // not including starting or cleaning up. - timeout time.Duration - - // limit is the maximum number of calls to the fuzz function the worker may - // make. The worker may make fewer calls, for example, if it finds an - // error early. If limit is zero, there is no limit on calls to the - // fuzz function. - limit int64 - - // warmup indicates whether this is a warmup input before fuzzing begins. If - // true, the input should not be fuzzed. - warmup bool - - // coverageData reflects the coordinator's current coverageMask. - coverageData []byte -} - -type fuzzResult struct { - // entry is an interesting value or a crasher. - entry CorpusEntry - - // crasherMsg is an error message from a crash. It's "" if no crash was found. - crasherMsg string - - // canMinimize is true if the worker should attempt to minimize this result. - // It may be false because an attempt has already been made. - canMinimize bool - - // coverageData is set if the worker found new coverage. - coverageData []byte - - // limit is the number of values the coordinator asked the worker - // to test. 0 if there was no limit. - limit int64 - - // count is the number of values the worker actually tested. - count int64 - - // totalDuration is the time the worker spent testing inputs. - totalDuration time.Duration - - // entryDuration is the time the worker spent execution an interesting result - entryDuration time.Duration -} - -type fuzzMinimizeInput struct { - // entry is an interesting value or crasher to minimize. - entry CorpusEntry - - // crasherMsg is an error message from a crash. It's "" if no crash was found. - // If set, the worker will attempt to find a smaller input that also produces - // an error, though not necessarily the same error. - crasherMsg string - - // limit is the maximum number of calls to the fuzz function the worker may - // make. The worker may make fewer calls, for example, if it can't reproduce - // an error. If limit is zero, there is no limit on calls to the fuzz function. - limit int64 - - // timeout is the time to spend minimizing this input. - // A zero timeout means no limit. - timeout time.Duration - - // keepCoverage is a set of coverage bits that entry found that were not in - // the coordinator's combined set. When minimizing, the worker should find an - // input that preserves at least one of these bits. keepCoverage is nil for - // crashing inputs. - keepCoverage []byte -} - -// coordinator holds channels that workers can use to communicate with -// the coordinator. -type coordinator struct { - opts CoordinateFuzzingOpts - - // startTime is the time we started the workers after loading the corpus. - // Used for logging. - startTime time.Time - - // inputC is sent values to fuzz by the coordinator. Any worker may receive - // values from this channel. Workers send results to resultC. - inputC chan fuzzInput - - // minimizeC is sent values to minimize by the coordinator. Any worker may - // receive values from this channel. Workers send results to resultC. - minimizeC chan fuzzMinimizeInput - - // resultC is sent results of fuzzing by workers. The coordinator - // receives these. Multiple types of messages are allowed. - resultC chan fuzzResult - - // count is the number of values fuzzed so far. - count int64 - - // countLastLog is the number of values fuzzed when the output was last - // logged. - countLastLog int64 - - // timeLastLog is the time at which the output was last logged. - timeLastLog time.Time - - // interestingCount is the number of unique interesting values which have - // been found this execution. - interestingCount int - - // warmupInputCount is the count of all entries in the corpus which will - // need to be received from workers to run once during warmup, but not fuzz. - // This could be for coverage data, or only for the purposes of verifying - // that the seed corpus doesn't have any crashers. See warmupRun. - warmupInputCount int - - // warmupInputLeft is the number of entries in the corpus which still need - // to be received from workers to run once during warmup, but not fuzz. - // See warmupInputLeft. - warmupInputLeft int - - // duration is the time spent fuzzing inside workers, not counting time - // starting up or tearing down. - duration time.Duration - - // countWaiting is the number of fuzzing executions the coordinator is - // waiting on workers to complete. - countWaiting int64 - - // corpus is a set of interesting values, including the seed corpus and - // generated values that workers reported as interesting. - corpus corpus - - // minimizationAllowed is true if one or more of the types of fuzz - // function's parameters can be minimized. - minimizationAllowed bool - - // inputQueue is a queue of inputs that workers should try fuzzing. This is - // initially populated from the seed corpus and cached inputs. More inputs - // may be added as new coverage is discovered. - inputQueue queue - - // minimizeQueue is a queue of inputs that caused errors or exposed new - // coverage. Workers should attempt to find smaller inputs that do the - // same thing. - minimizeQueue queue - - // crashMinimizing is the crash that is currently being minimized. - crashMinimizing *fuzzResult - - // coverageMask aggregates coverage that was found for all inputs in the - // corpus. Each byte represents a single basic execution block. Each set bit - // within the byte indicates that an input has triggered that block at least - // 1 << n times, where n is the position of the bit in the byte. For example, a - // value of 12 indicates that separate inputs have triggered this block - // between 4-7 times and 8-15 times. - coverageMask []byte -} - -func newCoordinator(opts CoordinateFuzzingOpts) (*coordinator, error) { - // Make sure all the seed corpus has marshaled data. - for i := range opts.Seed { - if opts.Seed[i].Data == nil && opts.Seed[i].Values != nil { - opts.Seed[i].Data = marshalCorpusFile(opts.Seed[i].Values...) - } - } - c := &coordinator{ - opts: opts, - startTime: time.Now(), - inputC: make(chan fuzzInput), - minimizeC: make(chan fuzzMinimizeInput), - resultC: make(chan fuzzResult), - timeLastLog: time.Now(), - corpus: corpus{hashes: make(map[[sha256.Size]byte]bool)}, - } - if err := c.readCache(); err != nil { - return nil, err - } - if opts.MinimizeLimit > 0 || opts.MinimizeTimeout > 0 { - for _, t := range opts.Types { - if isMinimizable(t) { - c.minimizationAllowed = true - break - } - } - } - - covSize := len(coverage()) - if covSize == 0 { - fmt.Fprintf(c.opts.Log, "warning: the test binary was not built with coverage instrumentation, so fuzzing will run without coverage guidance and may be inefficient\n") - // Even though a coverage-only run won't occur, we should still run all - // of the seed corpus to make sure there are no existing failures before - // we start fuzzing. - c.warmupInputCount = len(c.opts.Seed) - for _, e := range c.opts.Seed { - c.inputQueue.enqueue(e) - } - } else { - c.warmupInputCount = len(c.corpus.entries) - for _, e := range c.corpus.entries { - c.inputQueue.enqueue(e) - } - // Set c.coverageMask to a clean []byte full of zeros. - c.coverageMask = make([]byte, covSize) - } - c.warmupInputLeft = c.warmupInputCount - - if len(c.corpus.entries) == 0 { - fmt.Fprintf(c.opts.Log, "warning: starting with empty corpus\n") - var vals []any - for _, t := range opts.Types { - vals = append(vals, zeroValue(t)) - } - data := marshalCorpusFile(vals...) - h := sha256.Sum256(data) - name := fmt.Sprintf("%x", h[:4]) - c.addCorpusEntries(false, CorpusEntry{Path: name, Data: data}) - } - - return c, nil -} - -func (c *coordinator) updateStats(result fuzzResult) { - c.count += result.count - c.countWaiting -= result.limit - c.duration += result.totalDuration -} - -func (c *coordinator) logStats() { - now := time.Now() - if c.warmupRun() { - runSoFar := c.warmupInputCount - c.warmupInputLeft - if coverageEnabled { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, gathering baseline coverage: %d/%d completed\n", c.elapsed(), runSoFar, c.warmupInputCount) - } else { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, testing seed corpus: %d/%d completed\n", c.elapsed(), runSoFar, c.warmupInputCount) - } - } else if c.crashMinimizing != nil { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, minimizing\n", c.elapsed()) - } else { - rate := float64(c.count-c.countLastLog) / now.Sub(c.timeLastLog).Seconds() - if coverageEnabled { - total := c.warmupInputCount + c.interestingCount - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, execs: %d (%.0f/sec), new interesting: %d (total: %d)\n", c.elapsed(), c.count, rate, c.interestingCount, total) - } else { - fmt.Fprintf(c.opts.Log, "fuzz: elapsed: %s, execs: %d (%.0f/sec)\n", c.elapsed(), c.count, rate) - } - } - c.countLastLog = c.count - c.timeLastLog = now -} - -// peekInput returns the next value that should be sent to workers. -// If the number of executions is limited, the returned value includes -// a limit for one worker. If there are no executions left, peekInput returns -// a zero value and false. -// -// peekInput doesn't actually remove the input from the queue. The caller -// must call sentInput after sending the input. -// -// If the input queue is empty and the coverage/testing-only run has completed, -// queue refills it from the corpus. -func (c *coordinator) peekInput() (fuzzInput, bool) { - if c.opts.Limit > 0 && c.count+c.countWaiting >= c.opts.Limit { - // Already making the maximum number of calls to the fuzz function. - // Don't send more inputs right now. - return fuzzInput{}, false - } - if c.inputQueue.len == 0 { - if c.warmupRun() { - // Wait for coverage/testing-only run to finish before sending more - // inputs. - return fuzzInput{}, false - } - c.refillInputQueue() - } - - entry, ok := c.inputQueue.peek() - if !ok { - panic("input queue empty after refill") - } - input := fuzzInput{ - entry: entry.(CorpusEntry), - timeout: workerFuzzDuration, - warmup: c.warmupRun(), - } - if c.coverageMask != nil { - input.coverageData = bytes.Clone(c.coverageMask) - } - if input.warmup { - // No fuzzing will occur, but it should count toward the limit set by - // -fuzztime. - input.limit = 1 - return input, true - } - - if c.opts.Limit > 0 { - input.limit = c.opts.Limit / int64(c.opts.Parallel) - if c.opts.Limit%int64(c.opts.Parallel) > 0 { - input.limit++ - } - remaining := c.opts.Limit - c.count - c.countWaiting - if input.limit > remaining { - input.limit = remaining - } - } - return input, true -} - -// sentInput updates internal counters after an input is sent to c.inputC. -func (c *coordinator) sentInput(input fuzzInput) { - c.inputQueue.dequeue() - c.countWaiting += input.limit -} - -// refillInputQueue refills the input queue from the corpus after it becomes -// empty. -func (c *coordinator) refillInputQueue() { - for _, e := range c.corpus.entries { - c.inputQueue.enqueue(e) - } -} - -// queueForMinimization creates a fuzzMinimizeInput from result and adds it -// to the minimization queue to be sent to workers. -func (c *coordinator) queueForMinimization(result fuzzResult, keepCoverage []byte) { - if shouldPrintDebugInfo() { - c.debugLogf( - "queueing input for minimization, id: %s, parent: %s, keepCoverage: %t, crasher: %t", - result.entry.Path, - result.entry.Parent, - keepCoverage != nil, - result.crasherMsg != "", - ) - } - if result.crasherMsg != "" { - c.minimizeQueue.clear() - } - - input := fuzzMinimizeInput{ - entry: result.entry, - crasherMsg: result.crasherMsg, - keepCoverage: keepCoverage, - } - c.minimizeQueue.enqueue(input) -} - -// peekMinimizeInput returns the next input that should be sent to workers for -// minimization. -func (c *coordinator) peekMinimizeInput() (fuzzMinimizeInput, bool) { - if !c.canMinimize() { - // Already making the maximum number of calls to the fuzz function. - // Don't send more inputs right now. - return fuzzMinimizeInput{}, false - } - v, ok := c.minimizeQueue.peek() - if !ok { - return fuzzMinimizeInput{}, false - } - input := v.(fuzzMinimizeInput) - - if c.opts.MinimizeTimeout > 0 { - input.timeout = c.opts.MinimizeTimeout - } - if c.opts.MinimizeLimit > 0 { - input.limit = c.opts.MinimizeLimit - } else if c.opts.Limit > 0 { - if input.crasherMsg != "" { - input.limit = c.opts.Limit - } else { - input.limit = c.opts.Limit / int64(c.opts.Parallel) - if c.opts.Limit%int64(c.opts.Parallel) > 0 { - input.limit++ - } - } - } - if c.opts.Limit > 0 { - remaining := c.opts.Limit - c.count - c.countWaiting - if input.limit > remaining { - input.limit = remaining - } - } - return input, true -} - -// sentMinimizeInput removes an input from the minimization queue after it's -// sent to minimizeC. -func (c *coordinator) sentMinimizeInput(input fuzzMinimizeInput) { - c.minimizeQueue.dequeue() - c.countWaiting += input.limit -} - -// warmupRun returns true while the coordinator is running inputs without -// mutating them as a warmup before fuzzing. This could be to gather baseline -// coverage data for entries in the corpus, or to test all of the seed corpus -// for errors before fuzzing begins. -// -// The coordinator doesn't store coverage data in the cache with each input -// because that data would be invalid when counter offsets in the test binary -// change. -// -// When gathering coverage, the coordinator sends each entry to a worker to -// gather coverage for that entry only, without fuzzing or minimizing. This -// phase ends when all workers have finished, and the coordinator has a combined -// coverage map. -func (c *coordinator) warmupRun() bool { - return c.warmupInputLeft > 0 -} - -// updateCoverage sets bits in c.coverageMask that are set in newCoverage. -// updateCoverage returns the number of newly set bits. See the comment on -// coverageMask for the format. -func (c *coordinator) updateCoverage(newCoverage []byte) int { - if len(newCoverage) != len(c.coverageMask) { - panic(fmt.Sprintf("number of coverage counters changed at runtime: %d, expected %d", len(newCoverage), len(c.coverageMask))) - } - newBitCount := 0 - for i := range newCoverage { - diff := newCoverage[i] &^ c.coverageMask[i] - newBitCount += bits.OnesCount8(diff) - c.coverageMask[i] |= newCoverage[i] - } - return newBitCount -} - -// canMinimize returns whether the coordinator should attempt to find smaller -// inputs that reproduce a crash or new coverage. -func (c *coordinator) canMinimize() bool { - return c.minimizationAllowed && - (c.opts.Limit == 0 || c.count+c.countWaiting < c.opts.Limit) -} - -func (c *coordinator) elapsed() time.Duration { - return time.Since(c.startTime).Round(1 * time.Second) -} - -// readCache creates a combined corpus from seed values and values in the cache -// (in GOCACHE/fuzz). -// -// TODO(fuzzing): need a mechanism that can remove values that -// aren't useful anymore, for example, because they have the wrong type. -func (c *coordinator) readCache() error { - if _, err := c.addCorpusEntries(false, c.opts.Seed...); err != nil { - return err - } - entries, err := ReadCorpus(c.opts.CacheDir, c.opts.Types) - if err != nil { - if _, ok := err.(*MalformedCorpusError); !ok { - // It's okay if some files in the cache directory are malformed and - // are not included in the corpus, but fail if it's an I/O error. - return err - } - // TODO(jayconrod,katiehockman): consider printing some kind of warning - // indicating the number of files which were skipped because they are - // malformed. - } - if _, err := c.addCorpusEntries(false, entries...); err != nil { - return err - } - return nil -} - -// MalformedCorpusError is an error found while reading the corpus from the -// filesystem. All of the errors are stored in the errs list. The testing -// framework uses this to report malformed files in testdata. -type MalformedCorpusError struct { - errs []error -} - -func (e *MalformedCorpusError) Error() string { - var msgs []string - for _, s := range e.errs { - msgs = append(msgs, s.Error()) - } - return strings.Join(msgs, "\n") -} - -// ReadCorpus reads the corpus from the provided dir. The returned corpus -// entries are guaranteed to match the given types. Any malformed files will -// be saved in a MalformedCorpusError and returned, along with the most recent -// error. -func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) { - files, err := os.ReadDir(dir) - if os.IsNotExist(err) { - return nil, nil // No corpus to read - } else if err != nil { - return nil, fmt.Errorf("reading seed corpus from testdata: %v", err) - } - var corpus []CorpusEntry - var errs []error - for _, file := range files { - // TODO(jayconrod,katiehockman): determine when a file is a fuzzing input - // based on its name. We should only read files created by writeToCorpus. - // If we read ALL files, we won't be able to change the file format by - // changing the extension. We also won't be able to add files like - // README.txt explaining why the directory exists. - if file.IsDir() { - continue - } - filename := filepath.Join(dir, file.Name()) - data, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("failed to read corpus file: %v", err) - } - var vals []any - vals, err = readCorpusData(data, types) - if err != nil { - errs = append(errs, fmt.Errorf("%q: %v", filename, err)) - continue - } - corpus = append(corpus, CorpusEntry{Path: filename, Values: vals}) - } - if len(errs) > 0 { - return corpus, &MalformedCorpusError{errs: errs} - } - return corpus, nil -} - -func readCorpusData(data []byte, types []reflect.Type) ([]any, error) { - vals, err := unmarshalCorpusFile(data) - if err != nil { - return nil, fmt.Errorf("unmarshal: %v", err) - } - if err = CheckCorpus(vals, types); err != nil { - return nil, err - } - return vals, nil -} - -// CheckCorpus verifies that the types in vals match the expected types -// provided. -func CheckCorpus(vals []any, types []reflect.Type) error { - if len(vals) != len(types) { - return fmt.Errorf("wrong number of values in corpus entry: %d, want %d", len(vals), len(types)) - } - valsT := make([]reflect.Type, len(vals)) - for valsI, v := range vals { - valsT[valsI] = reflect.TypeOf(v) - } - for i := range types { - if valsT[i] != types[i] { - return fmt.Errorf("mismatched types in corpus entry: %v, want %v", valsT, types) - } - } - return nil -} - -// writeToCorpus atomically writes the given bytes to a new file in testdata. If -// the directory does not exist, it will create one. If the file already exists, -// writeToCorpus will not rewrite it. writeToCorpus sets entry.Path to the new -// file that was just written or an error if it failed. -func writeToCorpus(entry *CorpusEntry, dir string) (err error) { - sum := fmt.Sprintf("%x", sha256.Sum256(entry.Data))[:16] - entry.Path = filepath.Join(dir, sum) - if err := os.MkdirAll(dir, 0777); err != nil { - return err - } - if err := os.WriteFile(entry.Path, entry.Data, 0666); err != nil { - os.Remove(entry.Path) // remove partially written file - return err - } - return nil -} - -func testName(path string) string { - return filepath.Base(path) -} - -func zeroValue(t reflect.Type) any { - for _, v := range zeroVals { - if reflect.TypeOf(v) == t { - return v - } - } - panic(fmt.Sprintf("unsupported type: %v", t)) -} - -var zeroVals []any = []any{ - []byte(""), - string(""), - false, - byte(0), - rune(0), - float32(0), - float64(0), - int(0), - int8(0), - int16(0), - int32(0), - int64(0), - uint(0), - uint8(0), - uint16(0), - uint32(0), - uint64(0), -} - -var debugInfo = godebug.New("#fuzzdebug").Value() == "1" - -func shouldPrintDebugInfo() bool { - return debugInfo -} - -func (c *coordinator) debugLogf(format string, args ...any) { - t := time.Now().Format("2006-01-02 15:04:05.999999999") - fmt.Fprintf(c.opts.Log, t+" DEBUG "+format+"\n", args...) -} diff --git a/testing/internal/fuzz/mem.go b/testing/internal/fuzz/mem.go deleted file mode 100644 index 4155e4e8..00000000 --- a/testing/internal/fuzz/mem.go +++ /dev/null @@ -1,138 +0,0 @@ -// 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 fuzz - -import ( - "bytes" - "fmt" - "os" - "unsafe" -) - -// sharedMem manages access to a region of virtual memory mapped from a file, -// shared between multiple processes. The region includes space for a header and -// a value of variable length. -// -// When fuzzing, the coordinator creates a sharedMem from a temporary file for -// each worker. This buffer is used to pass values to fuzz between processes. -// Care must be taken to manage access to shared memory across processes; -// sharedMem provides no synchronization on its own. See workerComm for an -// explanation. -type sharedMem struct { - // f is the file mapped into memory. - f *os.File - - // region is the mapped region of virtual memory for f. The content of f may - // be read or written through this slice. - region []byte - - // removeOnClose is true if the file should be deleted by Close. - removeOnClose bool - - // sys contains OS-specific information. - sys sharedMemSys -} - -// sharedMemHeader stores metadata in shared memory. -type sharedMemHeader struct { - // count is the number of times the worker has called the fuzz function. - // May be reset by coordinator. - count int64 - - // valueLen is the number of bytes in region which should be read. - valueLen int - - // randState and randInc hold the state of a pseudo-random number generator. - randState, randInc uint64 - - // rawInMem is true if the region holds raw bytes, which occurs during - // minimization. If true after the worker fails during minimization, this - // indicates that an unrecoverable error occurred, and the region can be - // used to retrieve the raw bytes that caused the error. - rawInMem bool -} - -// sharedMemSize returns the size needed for a shared memory buffer that can -// contain values of the given size. -func sharedMemSize(valueSize int) int { - // TODO(jayconrod): set a reasonable maximum size per platform. - return int(unsafe.Sizeof(sharedMemHeader{})) + valueSize -} - -// sharedMemTempFile creates a new temporary file of the given size, then maps -// it into memory. The file will be removed when the Close method is called. -func sharedMemTempFile(size int) (m *sharedMem, err error) { - // Create a temporary file. - f, err := os.CreateTemp("", "fuzz-*") - if err != nil { - return nil, err - } - defer func() { - if err != nil { - f.Close() - os.Remove(f.Name()) - } - }() - - // Resize it to the correct size. - totalSize := sharedMemSize(size) - if err := f.Truncate(int64(totalSize)); err != nil { - return nil, err - } - - // Map the file into memory. - removeOnClose := true - return sharedMemMapFile(f, totalSize, removeOnClose) -} - -// header returns a pointer to metadata within the shared memory region. -func (m *sharedMem) header() *sharedMemHeader { - return (*sharedMemHeader)(unsafe.Pointer(&m.region[0])) -} - -// valueRef returns the value currently stored in shared memory. The returned -// slice points to shared memory; it is not a copy. -func (m *sharedMem) valueRef() []byte { - length := m.header().valueLen - valueOffset := int(unsafe.Sizeof(sharedMemHeader{})) - return m.region[valueOffset : valueOffset+length] -} - -// valueCopy returns a copy of the value stored in shared memory. -func (m *sharedMem) valueCopy() []byte { - ref := m.valueRef() - return bytes.Clone(ref) -} - -// setValue copies the data in b into the shared memory buffer and sets -// the length. len(b) must be less than or equal to the capacity of the buffer -// (as returned by cap(m.value())). -func (m *sharedMem) setValue(b []byte) { - v := m.valueRef() - if len(b) > cap(v) { - panic(fmt.Sprintf("value length %d larger than shared memory capacity %d", len(b), cap(v))) - } - m.header().valueLen = len(b) - copy(v[:cap(v)], b) -} - -// setValueLen sets the length of the shared memory buffer returned by valueRef -// to n, which may be at most the cap of that slice. -// -// Note that we can only store the length in the shared memory header. The full -// slice header contains a pointer, which is likely only valid for one process, -// since each process can map shared memory at a different virtual address. -func (m *sharedMem) setValueLen(n int) { - v := m.valueRef() - if n > cap(v) { - panic(fmt.Sprintf("length %d larger than shared memory capacity %d", n, cap(v))) - } - m.header().valueLen = n -} - -// TODO(jayconrod): add method to resize the buffer. We'll need that when the -// mutator can increase input length. Only the coordinator will be able to -// do it, since we'll need to send a message to the worker telling it to -// remap the file. diff --git a/testing/internal/fuzz/minimize.go b/testing/internal/fuzz/minimize.go deleted file mode 100644 index 0e410fb8..00000000 --- a/testing/internal/fuzz/minimize.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "reflect" -) - -func isMinimizable(t reflect.Type) bool { - return t == reflect.TypeOf("") || t == reflect.TypeOf([]byte(nil)) -} - -func minimizeBytes(v []byte, try func([]byte) bool, shouldStop func() bool) { - tmp := make([]byte, len(v)) - // If minimization was successful at any point during minimizeBytes, - // then the vals slice in (*workerServer).minimizeInput will point to - // tmp. Since tmp is altered while making new candidates, we need to - // make sure that it is equal to the correct value, v, before exiting - // this function. - defer copy(tmp, v) - - // First, try to cut the tail. - for n := 1024; n != 0; n /= 2 { - for len(v) > n { - if shouldStop() { - return - } - candidate := v[:len(v)-n] - if !try(candidate) { - break - } - // Set v to the new value to continue iterating. - v = candidate - } - } - - // Then, try to remove each individual byte. - for i := 0; i < len(v)-1; i++ { - if shouldStop() { - return - } - candidate := tmp[:len(v)-1] - copy(candidate[:i], v[:i]) - copy(candidate[i:], v[i+1:]) - if !try(candidate) { - continue - } - // Update v to delete the value at index i. - copy(v[i:], v[i+1:]) - v = v[:len(candidate)] - // v[i] is now different, so decrement i to redo this iteration - // of the loop with the new value. - i-- - } - - // Then, try to remove each possible subset of bytes. - for i := 0; i < len(v)-1; i++ { - copy(tmp, v[:i]) - for j := len(v); j > i+1; j-- { - if shouldStop() { - return - } - candidate := tmp[:len(v)-j+i] - copy(candidate[i:], v[j:]) - if !try(candidate) { - continue - } - // Update v and reset the loop with the new length. - copy(v[i:], v[j:]) - v = v[:len(candidate)] - j = len(v) - } - } - - // Then, try to make it more simplified and human-readable by trying to replace each - // byte with a printable character. - printableChars := []byte("012789ABCXYZabcxyz !\"#$%&'()*+,.") - for i, b := range v { - if shouldStop() { - return - } - - for _, pc := range printableChars { - v[i] = pc - if try(v) { - // Successful. Move on to the next byte in v. - break - } - // Unsuccessful. Revert v[i] back to original value. - v[i] = b - } - } -} diff --git a/testing/internal/fuzz/minimize_test.go b/testing/internal/fuzz/minimize_test.go deleted file mode 100644 index e7e23e5a..00000000 --- a/testing/internal/fuzz/minimize_test.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2021 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 darwin || freebsd || linux || openbsd || windows - -package fuzz - -import ( - "bytes" - "context" - "errors" - "fmt" - "reflect" - "testing" - "time" - "unicode" - "unicode/utf8" -) - -func TestMinimizeInput(t *testing.T) { - type testcase struct { - name string - fn func(CorpusEntry) error - input []any - expected []any - } - cases := []testcase{ - { - name: "ones_byte", - fn: func(e CorpusEntry) error { - b := e.Values[0].([]byte) - ones := 0 - for _, v := range b { - if v == 1 { - ones++ - } - } - if ones == 3 { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{[]byte{0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - expected: []any{[]byte{1, 1, 1}}, - }, - { - name: "single_bytes", - fn: func(e CorpusEntry) error { - b := e.Values[0].([]byte) - if len(b) < 2 { - return nil - } - if len(b) == 2 && b[0] == 1 && b[1] == 2 { - return nil - } - return fmt.Errorf("bad %v", e.Values[0]) - }, - input: []any{[]byte{1, 2, 3, 4, 5}}, - expected: []any{[]byte("00")}, - }, - { - name: "set_of_bytes", - fn: func(e CorpusEntry) error { - b := e.Values[0].([]byte) - if len(b) < 3 { - return nil - } - if bytes.Equal(b, []byte{0, 1, 2, 3, 4, 5}) || bytes.Equal(b, []byte{0, 4, 5}) { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{[]byte{0, 1, 2, 3, 4, 5}}, - expected: []any{[]byte{0, 4, 5}}, - }, - { - name: "non_ascii_bytes", - fn: func(e CorpusEntry) error { - b := e.Values[0].([]byte) - if len(b) == 3 { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{[]byte("ท")}, // ท is 3 bytes - expected: []any{[]byte("000")}, - }, - { - name: "ones_string", - fn: func(e CorpusEntry) error { - b := e.Values[0].(string) - ones := 0 - for _, v := range b { - if v == '1' { - ones++ - } - } - if ones == 3 { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{"001010001000000000000000000"}, - expected: []any{"111"}, - }, - { - name: "string_length", - fn: func(e CorpusEntry) error { - b := e.Values[0].(string) - if len(b) == 5 { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{"zzzzz"}, - expected: []any{"00000"}, - }, - { - name: "string_with_letter", - fn: func(e CorpusEntry) error { - b := e.Values[0].(string) - r, _ := utf8.DecodeRune([]byte(b)) - if unicode.IsLetter(r) { - return fmt.Errorf("bad %v", e.Values[0]) - } - return nil - }, - input: []any{"ZZZZZ"}, - expected: []any{"A"}, - }, - } - - for _, tc := range cases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - ws := &workerServer{ - fuzzFn: func(e CorpusEntry) (time.Duration, error) { - return time.Second, tc.fn(e) - }, - } - mem := &sharedMem{region: make([]byte, 100)} // big enough to hold value and header - vals := tc.input - success, err := ws.minimizeInput(context.Background(), vals, mem, minimizeArgs{}) - if !success { - t.Errorf("minimizeInput did not succeed") - } - if err == nil { - t.Fatal("minimizeInput didn't provide an error") - } - if expected := fmt.Sprintf("bad %v", tc.expected[0]); err.Error() != expected { - t.Errorf("unexpected error: got %q, want %q", err, expected) - } - if !reflect.DeepEqual(vals, tc.expected) { - t.Errorf("unexpected results: got %v, want %v", vals, tc.expected) - } - }) - } -} - -// TestMinimizeFlaky checks that if we're minimizing an interesting -// input and a flaky failure occurs, that minimization was not indicated -// to be successful, and the error isn't returned (since it's flaky). -func TestMinimizeFlaky(t *testing.T) { - ws := &workerServer{fuzzFn: func(e CorpusEntry) (time.Duration, error) { - return time.Second, errors.New("ohno") - }} - mem := &sharedMem{region: make([]byte, 100)} // big enough to hold value and header - vals := []any{[]byte(nil)} - args := minimizeArgs{KeepCoverage: make([]byte, len(coverageSnapshot))} - success, err := ws.minimizeInput(context.Background(), vals, mem, args) - if success { - t.Error("unexpected success") - } - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if count := mem.header().count; count != 1 { - t.Errorf("count: got %d, want 1", count) - } -} diff --git a/testing/internal/fuzz/mutator.go b/testing/internal/fuzz/mutator.go deleted file mode 100644 index 9bba0d62..00000000 --- a/testing/internal/fuzz/mutator.go +++ /dev/null @@ -1,293 +0,0 @@ -// 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 fuzz - -import ( - "encoding/binary" - "fmt" - "math" - "unsafe" -) - -type mutator struct { - r mutatorRand - scratch []byte // scratch slice to avoid additional allocations -} - -func newMutator() *mutator { - return &mutator{r: newPcgRand()} -} - -func (m *mutator) rand(n int) int { - return m.r.intn(n) -} - -func (m *mutator) randByteOrder() binary.ByteOrder { - if m.r.bool() { - return binary.LittleEndian - } - return binary.BigEndian -} - -// chooseLen chooses length of range mutation in range [1,n]. It gives -// preference to shorter ranges. -func (m *mutator) chooseLen(n int) int { - switch x := m.rand(100); { - case x < 90: - return m.rand(min(8, n)) + 1 - case x < 99: - return m.rand(min(32, n)) + 1 - default: - return m.rand(n) + 1 - } -} - -// mutate performs several mutations on the provided values. -func (m *mutator) mutate(vals []any, maxBytes int) { - // TODO(katiehockman): pull some of these functions into helper methods and - // test that each case is working as expected. - // TODO(katiehockman): perform more types of mutations for []byte. - - // maxPerVal will represent the maximum number of bytes that each value be - // allowed after mutating, giving an equal amount of capacity to each line. - // Allow a little wiggle room for the encoding. - maxPerVal := maxBytes/len(vals) - 100 - - // Pick a random value to mutate. - // TODO: consider mutating more than one value at a time. - i := m.rand(len(vals)) - switch v := vals[i].(type) { - case int: - vals[i] = int(m.mutateInt(int64(v), maxInt)) - case int8: - vals[i] = int8(m.mutateInt(int64(v), math.MaxInt8)) - case int16: - vals[i] = int16(m.mutateInt(int64(v), math.MaxInt16)) - case int64: - vals[i] = m.mutateInt(v, maxInt) - case uint: - vals[i] = uint(m.mutateUInt(uint64(v), maxUint)) - case uint16: - vals[i] = uint16(m.mutateUInt(uint64(v), math.MaxUint16)) - case uint32: - vals[i] = uint32(m.mutateUInt(uint64(v), math.MaxUint32)) - case uint64: - vals[i] = m.mutateUInt(v, maxUint) - case float32: - vals[i] = float32(m.mutateFloat(float64(v), math.MaxFloat32)) - case float64: - vals[i] = m.mutateFloat(v, math.MaxFloat64) - case bool: - if m.rand(2) == 1 { - vals[i] = !v // 50% chance of flipping the bool - } - case rune: // int32 - vals[i] = rune(m.mutateInt(int64(v), math.MaxInt32)) - case byte: // uint8 - vals[i] = byte(m.mutateUInt(uint64(v), math.MaxUint8)) - case string: - if len(v) > maxPerVal { - panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v))) - } - if cap(m.scratch) < maxPerVal { - m.scratch = append(make([]byte, 0, maxPerVal), v...) - } else { - m.scratch = m.scratch[:len(v)] - copy(m.scratch, v) - } - m.mutateBytes(&m.scratch) - vals[i] = string(m.scratch) - case []byte: - if len(v) > maxPerVal { - panic(fmt.Sprintf("cannot mutate bytes of length %d", len(v))) - } - if cap(m.scratch) < maxPerVal { - m.scratch = append(make([]byte, 0, maxPerVal), v...) - } else { - m.scratch = m.scratch[:len(v)] - copy(m.scratch, v) - } - m.mutateBytes(&m.scratch) - vals[i] = m.scratch - default: - panic(fmt.Sprintf("type not supported for mutating: %T", vals[i])) - } -} - -func (m *mutator) mutateInt(v, maxValue int64) int64 { - var max int64 - for { - max = 100 - switch m.rand(2) { - case 0: - // Add a random number - if v >= maxValue { - continue - } - if v > 0 && maxValue-v < max { - // Don't let v exceed maxValue - max = maxValue - v - } - v += int64(1 + m.rand(int(max))) - return v - case 1: - // Subtract a random number - if v <= -maxValue { - continue - } - if v < 0 && maxValue+v < max { - // Don't let v drop below -maxValue - max = maxValue + v - } - v -= int64(1 + m.rand(int(max))) - return v - } - } -} - -func (m *mutator) mutateUInt(v, maxValue uint64) uint64 { - var max uint64 - for { - max = 100 - switch m.rand(2) { - case 0: - // Add a random number - if v >= maxValue { - continue - } - if v > 0 && maxValue-v < max { - // Don't let v exceed maxValue - max = maxValue - v - } - - v += uint64(1 + m.rand(int(max))) - return v - case 1: - // Subtract a random number - if v <= 0 { - continue - } - if v < max { - // Don't let v drop below 0 - max = v - } - v -= uint64(1 + m.rand(int(max))) - return v - } - } -} - -func (m *mutator) mutateFloat(v, maxValue float64) float64 { - var max float64 - for { - switch m.rand(4) { - case 0: - // Add a random number - if v >= maxValue { - continue - } - max = 100 - if v > 0 && maxValue-v < max { - // Don't let v exceed maxValue - max = maxValue - v - } - v += float64(1 + m.rand(int(max))) - return v - case 1: - // Subtract a random number - if v <= -maxValue { - continue - } - max = 100 - if v < 0 && maxValue+v < max { - // Don't let v drop below -maxValue - max = maxValue + v - } - v -= float64(1 + m.rand(int(max))) - return v - case 2: - // Multiply by a random number - absV := math.Abs(v) - if v == 0 || absV >= maxValue { - continue - } - max = 10 - if maxValue/absV < max { - // Don't let v go beyond the minimum or maximum value - max = maxValue / absV - } - v *= float64(1 + m.rand(int(max))) - return v - case 3: - // Divide by a random number - if v == 0 { - continue - } - v /= float64(1 + m.rand(10)) - return v - } - } -} - -type byteSliceMutator func(*mutator, []byte) []byte - -var byteSliceMutators = []byteSliceMutator{ - byteSliceRemoveBytes, - byteSliceInsertRandomBytes, - byteSliceDuplicateBytes, - byteSliceOverwriteBytes, - byteSliceBitFlip, - byteSliceXORByte, - byteSliceSwapByte, - byteSliceArithmeticUint8, - byteSliceArithmeticUint16, - byteSliceArithmeticUint32, - byteSliceArithmeticUint64, - byteSliceOverwriteInterestingUint8, - byteSliceOverwriteInterestingUint16, - byteSliceOverwriteInterestingUint32, - byteSliceInsertConstantBytes, - byteSliceOverwriteConstantBytes, - byteSliceShuffleBytes, - byteSliceSwapBytes, -} - -func (m *mutator) mutateBytes(ptrB *[]byte) { - b := *ptrB - defer func() { - if unsafe.SliceData(*ptrB) != unsafe.SliceData(b) { - panic("data moved to new address") - } - *ptrB = b - }() - - for { - mut := byteSliceMutators[m.rand(len(byteSliceMutators))] - if mutated := mut(m, b); mutated != nil { - b = mutated - return - } - } -} - -var ( - interesting8 = []int8{-128, -1, 0, 1, 16, 32, 64, 100, 127} - interesting16 = []int16{-32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767} - interesting32 = []int32{-2147483648, -100663046, -32769, 32768, 65535, 65536, 100663045, 2147483647} -) - -const ( - maxUint = uint64(^uint(0)) - maxInt = int64(maxUint >> 1) -) - -func init() { - for _, v := range interesting8 { - interesting16 = append(interesting16, int16(v)) - } - for _, v := range interesting16 { - interesting32 = append(interesting32, int32(v)) - } -} diff --git a/testing/internal/fuzz/mutator_test.go b/testing/internal/fuzz/mutator_test.go deleted file mode 100644 index cea7e2e3..00000000 --- a/testing/internal/fuzz/mutator_test.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "bytes" - "fmt" - "os" - "strconv" - "testing" -) - -func BenchmarkMutatorBytes(b *testing.B) { - origEnv := os.Getenv("GODEBUG") - defer func() { os.Setenv("GODEBUG", origEnv) }() - os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv)) - m := newMutator() - - for _, size := range []int{ - 1, - 10, - 100, - 1000, - 10000, - 100000, - } { - b.Run(strconv.Itoa(size), func(b *testing.B) { - buf := make([]byte, size) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - // resize buffer to the correct shape and reset the PCG - buf = buf[0:size] - m.r = newPcgRand() - m.mutate([]any{buf}, workerSharedMemSize) - } - }) - } -} - -func BenchmarkMutatorString(b *testing.B) { - origEnv := os.Getenv("GODEBUG") - defer func() { os.Setenv("GODEBUG", origEnv) }() - os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv)) - m := newMutator() - - for _, size := range []int{ - 1, - 10, - 100, - 1000, - 10000, - 100000, - } { - b.Run(strconv.Itoa(size), func(b *testing.B) { - buf := make([]byte, size) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - // resize buffer to the correct shape and reset the PCG - buf = buf[0:size] - m.r = newPcgRand() - m.mutate([]any{string(buf)}, workerSharedMemSize) - } - }) - } -} - -func BenchmarkMutatorAllBasicTypes(b *testing.B) { - origEnv := os.Getenv("GODEBUG") - defer func() { os.Setenv("GODEBUG", origEnv) }() - os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv)) - m := newMutator() - - types := []any{ - []byte(""), - string(""), - false, - float32(0), - float64(0), - int(0), - int8(0), - int16(0), - int32(0), - int64(0), - uint8(0), - uint16(0), - uint32(0), - uint64(0), - } - - for _, t := range types { - b.Run(fmt.Sprintf("%T", t), func(b *testing.B) { - for i := 0; i < b.N; i++ { - m.r = newPcgRand() - m.mutate([]any{t}, workerSharedMemSize) - } - }) - } -} - -func TestStringImmutability(t *testing.T) { - v := []any{"hello"} - m := newMutator() - m.mutate(v, 1024) - original := v[0].(string) - originalCopy := make([]byte, len(original)) - copy(originalCopy, []byte(original)) - for i := 0; i < 25; i++ { - m.mutate(v, 1024) - } - if !bytes.Equal([]byte(original), originalCopy) { - t.Fatalf("string was mutated: got %x, want %x", []byte(original), originalCopy) - } -} diff --git a/testing/internal/fuzz/mutators_byteslice.go b/testing/internal/fuzz/mutators_byteslice.go deleted file mode 100644 index d9dab1df..00000000 --- a/testing/internal/fuzz/mutators_byteslice.go +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2021 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 fuzz - -// byteSliceRemoveBytes removes a random chunk of bytes from b. -func byteSliceRemoveBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - pos0 := m.rand(len(b)) - pos1 := pos0 + m.chooseLen(len(b)-pos0) - copy(b[pos0:], b[pos1:]) - b = b[:len(b)-(pos1-pos0)] - return b -} - -// byteSliceInsertRandomBytes inserts a chunk of random bytes into b at a random -// position. -func byteSliceInsertRandomBytes(m *mutator, b []byte) []byte { - pos := m.rand(len(b) + 1) - n := m.chooseLen(1024) - if len(b)+n >= cap(b) { - return nil - } - b = b[:len(b)+n] - copy(b[pos+n:], b[pos:]) - for i := 0; i < n; i++ { - b[pos+i] = byte(m.rand(256)) - } - return b -} - -// byteSliceDuplicateBytes duplicates a chunk of bytes in b and inserts it into -// a random position. -func byteSliceDuplicateBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - src := m.rand(len(b)) - dst := m.rand(len(b)) - for dst == src { - dst = m.rand(len(b)) - } - n := m.chooseLen(len(b) - src) - // Use the end of the slice as scratch space to avoid doing an - // allocation. If the slice is too small abort and try something - // else. - if len(b)+(n*2) >= cap(b) { - return nil - } - end := len(b) - // Increase the size of b to fit the duplicated block as well as - // some extra working space - b = b[:end+(n*2)] - // Copy the block of bytes we want to duplicate to the end of the - // slice - copy(b[end+n:], b[src:src+n]) - // Shift the bytes after the splice point n positions to the right - // to make room for the new block - copy(b[dst+n:end+n], b[dst:end]) - // Insert the duplicate block into the splice point - copy(b[dst:], b[end+n:]) - b = b[:end+n] - return b -} - -// byteSliceOverwriteBytes overwrites a chunk of b with another chunk of b. -func byteSliceOverwriteBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - src := m.rand(len(b)) - dst := m.rand(len(b)) - for dst == src { - dst = m.rand(len(b)) - } - n := m.chooseLen(len(b) - src - 1) - copy(b[dst:], b[src:src+n]) - return b -} - -// byteSliceBitFlip flips a random bit in a random byte in b. -func byteSliceBitFlip(m *mutator, b []byte) []byte { - if len(b) == 0 { - return nil - } - pos := m.rand(len(b)) - b[pos] ^= 1 << uint(m.rand(8)) - return b -} - -// byteSliceXORByte XORs a random byte in b with a random value. -func byteSliceXORByte(m *mutator, b []byte) []byte { - if len(b) == 0 { - return nil - } - pos := m.rand(len(b)) - // In order to avoid a no-op (where the random value matches - // the existing value), use XOR instead of just setting to - // the random value. - b[pos] ^= byte(1 + m.rand(255)) - return b -} - -// byteSliceSwapByte swaps two random bytes in b. -func byteSliceSwapByte(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - src := m.rand(len(b)) - dst := m.rand(len(b)) - for dst == src { - dst = m.rand(len(b)) - } - b[src], b[dst] = b[dst], b[src] - return b -} - -// byteSliceArithmeticUint8 adds/subtracts from a random byte in b. -func byteSliceArithmeticUint8(m *mutator, b []byte) []byte { - if len(b) == 0 { - return nil - } - pos := m.rand(len(b)) - v := byte(m.rand(35) + 1) - if m.r.bool() { - b[pos] += v - } else { - b[pos] -= v - } - return b -} - -// byteSliceArithmeticUint16 adds/subtracts from a random uint16 in b. -func byteSliceArithmeticUint16(m *mutator, b []byte) []byte { - if len(b) < 2 { - return nil - } - v := uint16(m.rand(35) + 1) - if m.r.bool() { - v = 0 - v - } - pos := m.rand(len(b) - 1) - enc := m.randByteOrder() - enc.PutUint16(b[pos:], enc.Uint16(b[pos:])+v) - return b -} - -// byteSliceArithmeticUint32 adds/subtracts from a random uint32 in b. -func byteSliceArithmeticUint32(m *mutator, b []byte) []byte { - if len(b) < 4 { - return nil - } - v := uint32(m.rand(35) + 1) - if m.r.bool() { - v = 0 - v - } - pos := m.rand(len(b) - 3) - enc := m.randByteOrder() - enc.PutUint32(b[pos:], enc.Uint32(b[pos:])+v) - return b -} - -// byteSliceArithmeticUint64 adds/subtracts from a random uint64 in b. -func byteSliceArithmeticUint64(m *mutator, b []byte) []byte { - if len(b) < 8 { - return nil - } - v := uint64(m.rand(35) + 1) - if m.r.bool() { - v = 0 - v - } - pos := m.rand(len(b) - 7) - enc := m.randByteOrder() - enc.PutUint64(b[pos:], enc.Uint64(b[pos:])+v) - return b -} - -// byteSliceOverwriteInterestingUint8 overwrites a random byte in b with an interesting -// value. -func byteSliceOverwriteInterestingUint8(m *mutator, b []byte) []byte { - if len(b) == 0 { - return nil - } - pos := m.rand(len(b)) - b[pos] = byte(interesting8[m.rand(len(interesting8))]) - return b -} - -// byteSliceOverwriteInterestingUint16 overwrites a random uint16 in b with an interesting -// value. -func byteSliceOverwriteInterestingUint16(m *mutator, b []byte) []byte { - if len(b) < 2 { - return nil - } - pos := m.rand(len(b) - 1) - v := uint16(interesting16[m.rand(len(interesting16))]) - m.randByteOrder().PutUint16(b[pos:], v) - return b -} - -// byteSliceOverwriteInterestingUint32 overwrites a random uint16 in b with an interesting -// value. -func byteSliceOverwriteInterestingUint32(m *mutator, b []byte) []byte { - if len(b) < 4 { - return nil - } - pos := m.rand(len(b) - 3) - v := uint32(interesting32[m.rand(len(interesting32))]) - m.randByteOrder().PutUint32(b[pos:], v) - return b -} - -// byteSliceInsertConstantBytes inserts a chunk of constant bytes into a random position in b. -func byteSliceInsertConstantBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - dst := m.rand(len(b)) - // TODO(rolandshoemaker,katiehockman): 4096 was mainly picked - // randomly. We may want to either pick a much larger value - // (AFL uses 32768, paired with a similar impl to chooseLen - // which biases towards smaller lengths that grow over time), - // or set the max based on characteristics of the corpus - // (libFuzzer sets a min/max based on the min/max size of - // entries in the corpus and then picks uniformly from - // that range). - n := m.chooseLen(4096) - if len(b)+n >= cap(b) { - return nil - } - b = b[:len(b)+n] - copy(b[dst+n:], b[dst:]) - rb := byte(m.rand(256)) - for i := dst; i < dst+n; i++ { - b[i] = rb - } - return b -} - -// byteSliceOverwriteConstantBytes overwrites a chunk of b with constant bytes. -func byteSliceOverwriteConstantBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - dst := m.rand(len(b)) - n := m.chooseLen(len(b) - dst) - rb := byte(m.rand(256)) - for i := dst; i < dst+n; i++ { - b[i] = rb - } - return b -} - -// byteSliceShuffleBytes shuffles a chunk of bytes in b. -func byteSliceShuffleBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - dst := m.rand(len(b)) - n := m.chooseLen(len(b) - dst) - if n <= 2 { - return nil - } - // Start at the end of the range, and iterate backwards - // to dst, swapping each element with another element in - // dst:dst+n (Fisher-Yates shuffle). - for i := n - 1; i > 0; i-- { - j := m.rand(i + 1) - b[dst+i], b[dst+j] = b[dst+j], b[dst+i] - } - return b -} - -// byteSliceSwapBytes swaps two chunks of bytes in b. -func byteSliceSwapBytes(m *mutator, b []byte) []byte { - if len(b) <= 1 { - return nil - } - src := m.rand(len(b)) - dst := m.rand(len(b)) - for dst == src { - dst = m.rand(len(b)) - } - // Choose the random length as len(b) - max(src, dst) - // so that we don't attempt to swap a chunk that extends - // beyond the end of the slice - max := dst - if src > max { - max = src - } - n := m.chooseLen(len(b) - max - 1) - // Check that neither chunk intersect, so that we don't end up - // duplicating parts of the input, rather than swapping them - if src > dst && dst+n >= src || dst > src && src+n >= dst { - return nil - } - // Use the end of the slice as scratch space to avoid doing an - // allocation. If the slice is too small abort and try something - // else. - if len(b)+n >= cap(b) { - return nil - } - end := len(b) - b = b[:end+n] - copy(b[end:], b[dst:dst+n]) - copy(b[dst:], b[src:src+n]) - copy(b[src:], b[end:]) - b = b[:end] - return b -} diff --git a/testing/internal/fuzz/mutators_byteslice_test.go b/testing/internal/fuzz/mutators_byteslice_test.go deleted file mode 100644 index b12ef6cb..00000000 --- a/testing/internal/fuzz/mutators_byteslice_test.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "bytes" - "fmt" - "testing" -) - -type mockRand struct { - values []int - counter int - b bool -} - -func (mr *mockRand) uint32() uint32 { - c := mr.values[mr.counter] - mr.counter++ - return uint32(c) -} - -func (mr *mockRand) intn(n int) int { - c := mr.values[mr.counter] - mr.counter++ - return c % n -} - -func (mr *mockRand) uint32n(n uint32) uint32 { - c := mr.values[mr.counter] - mr.counter++ - return uint32(c) % n -} - -func (mr *mockRand) bool() bool { - b := mr.b - mr.b = !mr.b - return b -} - -func (mr *mockRand) save(*uint64, *uint64) { - panic("unimplemented") -} - -func (mr *mockRand) restore(uint64, uint64) { - panic("unimplemented") -} - -func TestByteSliceMutators(t *testing.T) { - for _, tc := range []struct { - name string - mutator func(*mutator, []byte) []byte - randVals []int - input []byte - expected []byte - }{ - { - name: "byteSliceRemoveBytes", - mutator: byteSliceRemoveBytes, - input: []byte{1, 2, 3, 4}, - expected: []byte{4}, - }, - { - name: "byteSliceInsertRandomBytes", - mutator: byteSliceInsertRandomBytes, - input: make([]byte, 4, 8), - expected: []byte{3, 4, 5, 0, 0, 0, 0}, - }, - { - name: "byteSliceDuplicateBytes", - mutator: byteSliceDuplicateBytes, - input: append(make([]byte, 0, 13), []byte{1, 2, 3, 4}...), - expected: []byte{1, 1, 2, 3, 4, 2, 3, 4}, - }, - { - name: "byteSliceOverwriteBytes", - mutator: byteSliceOverwriteBytes, - input: []byte{1, 2, 3, 4}, - expected: []byte{1, 1, 3, 4}, - }, - { - name: "byteSliceBitFlip", - mutator: byteSliceBitFlip, - input: []byte{1, 2, 3, 4}, - expected: []byte{3, 2, 3, 4}, - }, - { - name: "byteSliceXORByte", - mutator: byteSliceXORByte, - input: []byte{1, 2, 3, 4}, - expected: []byte{3, 2, 3, 4}, - }, - { - name: "byteSliceSwapByte", - mutator: byteSliceSwapByte, - input: []byte{1, 2, 3, 4}, - expected: []byte{2, 1, 3, 4}, - }, - { - name: "byteSliceArithmeticUint8", - mutator: byteSliceArithmeticUint8, - input: []byte{1, 2, 3, 4}, - expected: []byte{255, 2, 3, 4}, - }, - { - name: "byteSliceArithmeticUint16", - mutator: byteSliceArithmeticUint16, - input: []byte{1, 2, 3, 4}, - expected: []byte{1, 3, 3, 4}, - }, - { - name: "byteSliceArithmeticUint32", - mutator: byteSliceArithmeticUint32, - input: []byte{1, 2, 3, 4}, - expected: []byte{2, 2, 3, 4}, - }, - { - name: "byteSliceArithmeticUint64", - mutator: byteSliceArithmeticUint64, - input: []byte{1, 2, 3, 4, 5, 6, 7, 8}, - expected: []byte{2, 2, 3, 4, 5, 6, 7, 8}, - }, - { - name: "byteSliceOverwriteInterestingUint8", - mutator: byteSliceOverwriteInterestingUint8, - input: []byte{1, 2, 3, 4}, - expected: []byte{255, 2, 3, 4}, - }, - { - name: "byteSliceOverwriteInterestingUint16", - mutator: byteSliceOverwriteInterestingUint16, - input: []byte{1, 2, 3, 4}, - expected: []byte{255, 127, 3, 4}, - }, - { - name: "byteSliceOverwriteInterestingUint32", - mutator: byteSliceOverwriteInterestingUint32, - input: []byte{1, 2, 3, 4}, - expected: []byte{250, 0, 0, 250}, - }, - { - name: "byteSliceInsertConstantBytes", - mutator: byteSliceInsertConstantBytes, - input: append(make([]byte, 0, 8), []byte{1, 2, 3, 4}...), - expected: []byte{3, 3, 3, 1, 2, 3, 4}, - }, - { - name: "byteSliceOverwriteConstantBytes", - mutator: byteSliceOverwriteConstantBytes, - input: []byte{1, 2, 3, 4}, - expected: []byte{3, 3, 3, 4}, - }, - { - name: "byteSliceShuffleBytes", - mutator: byteSliceShuffleBytes, - input: []byte{1, 2, 3, 4}, - expected: []byte{2, 3, 1, 4}, - }, - { - name: "byteSliceSwapBytes", - mutator: byteSliceSwapBytes, - randVals: []int{0, 2, 0, 2}, - input: append(make([]byte, 0, 9), []byte{1, 2, 3, 4}...), - expected: []byte{3, 2, 1, 4}, - }, - } { - t.Run(tc.name, func(t *testing.T) { - r := &mockRand{values: []int{0, 1, 2, 3, 4, 5}} - if tc.randVals != nil { - r.values = tc.randVals - } - m := &mutator{r: r} - b := tc.mutator(m, tc.input) - if !bytes.Equal(b, tc.expected) { - t.Errorf("got %x, want %x", b, tc.expected) - } - }) - } -} - -func BenchmarkByteSliceMutators(b *testing.B) { - tests := [...]struct { - name string - mutator func(*mutator, []byte) []byte - }{ - {"RemoveBytes", byteSliceRemoveBytes}, - {"InsertRandomBytes", byteSliceInsertRandomBytes}, - {"DuplicateBytes", byteSliceDuplicateBytes}, - {"OverwriteBytes", byteSliceOverwriteBytes}, - {"BitFlip", byteSliceBitFlip}, - {"XORByte", byteSliceXORByte}, - {"SwapByte", byteSliceSwapByte}, - {"ArithmeticUint8", byteSliceArithmeticUint8}, - {"ArithmeticUint16", byteSliceArithmeticUint16}, - {"ArithmeticUint32", byteSliceArithmeticUint32}, - {"ArithmeticUint64", byteSliceArithmeticUint64}, - {"OverwriteInterestingUint8", byteSliceOverwriteInterestingUint8}, - {"OverwriteInterestingUint16", byteSliceOverwriteInterestingUint16}, - {"OverwriteInterestingUint32", byteSliceOverwriteInterestingUint32}, - {"InsertConstantBytes", byteSliceInsertConstantBytes}, - {"OverwriteConstantBytes", byteSliceOverwriteConstantBytes}, - {"ShuffleBytes", byteSliceShuffleBytes}, - {"SwapBytes", byteSliceSwapBytes}, - } - - for _, tc := range tests { - b.Run(tc.name, func(b *testing.B) { - for size := 64; size <= 1024; size *= 2 { - b.Run(fmt.Sprintf("%d", size), func(b *testing.B) { - m := &mutator{r: newPcgRand()} - input := make([]byte, size) - for i := 0; i < b.N; i++ { - tc.mutator(m, input) - } - }) - } - }) - } -} diff --git a/testing/internal/fuzz/pcg.go b/testing/internal/fuzz/pcg.go deleted file mode 100644 index b8251043..00000000 --- a/testing/internal/fuzz/pcg.go +++ /dev/null @@ -1,139 +0,0 @@ -// 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 fuzz - -import ( - "math/bits" - "os" - "strconv" - "strings" - "sync/atomic" - "time" -) - -type mutatorRand interface { - uint32() uint32 - intn(int) int - uint32n(uint32) uint32 - bool() bool - - save(randState, randInc *uint64) - restore(randState, randInc uint64) -} - -// The functions in pcg implement a 32 bit PRNG with a 64 bit period: pcg xsh rr -// 64 32. See https://www.pcg-random.org/ for more information. This -// implementation is geared specifically towards the needs of fuzzing: Simple -// creation and use, no reproducibility, no concurrency safety, just the -// necessary methods, optimized for speed. - -var globalInc atomic.Uint64 // PCG stream - -const multiplier uint64 = 6364136223846793005 - -// pcgRand is a PRNG. It should not be copied or shared. No Rand methods are -// concurrency safe. -type pcgRand struct { - noCopy noCopy // help avoid mistakes: ask vet to ensure that we don't make a copy - state uint64 - inc uint64 -} - -func godebugSeed() *int { - debug := strings.Split(os.Getenv("GODEBUG"), ",") - for _, f := range debug { - if strings.HasPrefix(f, "fuzzseed=") { - seed, err := strconv.Atoi(strings.TrimPrefix(f, "fuzzseed=")) - if err != nil { - panic("malformed fuzzseed") - } - return &seed - } - } - return nil -} - -// newPcgRand generates a new, seeded Rand, ready for use. -func newPcgRand() *pcgRand { - r := new(pcgRand) - now := uint64(time.Now().UnixNano()) - if seed := godebugSeed(); seed != nil { - now = uint64(*seed) - } - inc := globalInc.Add(1) - r.state = now - r.inc = (inc << 1) | 1 - r.step() - r.state += now - r.step() - return r -} - -func (r *pcgRand) step() { - r.state *= multiplier - r.state += r.inc -} - -func (r *pcgRand) save(randState, randInc *uint64) { - *randState = r.state - *randInc = r.inc -} - -func (r *pcgRand) restore(randState, randInc uint64) { - r.state = randState - r.inc = randInc -} - -// uint32 returns a pseudo-random uint32. -func (r *pcgRand) uint32() uint32 { - x := r.state - r.step() - return bits.RotateLeft32(uint32(((x>>18)^x)>>27), -int(x>>59)) -} - -// intn returns a pseudo-random number in [0, n). -// n must fit in a uint32. -func (r *pcgRand) intn(n int) int { - if int(uint32(n)) != n { - panic("large Intn") - } - return int(r.uint32n(uint32(n))) -} - -// uint32n returns a pseudo-random number in [0, n). -// -// For implementation details, see: -// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction -// https://lemire.me/blog/2016/06/30/fast-random-shuffling -func (r *pcgRand) uint32n(n uint32) uint32 { - v := r.uint32() - prod := uint64(v) * uint64(n) - low := uint32(prod) - if low < n { - thresh := uint32(-int32(n)) % n - for low < thresh { - v = r.uint32() - prod = uint64(v) * uint64(n) - low = uint32(prod) - } - } - return uint32(prod >> 32) -} - -// bool generates a random bool. -func (r *pcgRand) bool() bool { - return r.uint32()&1 == 0 -} - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://golang.org/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} -func (*noCopy) Unlock() {} diff --git a/testing/internal/fuzz/queue.go b/testing/internal/fuzz/queue.go deleted file mode 100644 index 195d6eb7..00000000 --- a/testing/internal/fuzz/queue.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2021 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 fuzz - -// queue holds a growable sequence of inputs for fuzzing and minimization. -// -// For now, this is a simple ring buffer -// (https://en.wikipedia.org/wiki/Circular_buffer). -// -// TODO(golang.org/issue/46224): use a prioritization algorithm based on input -// size, previous duration, coverage, and any other metrics that seem useful. -type queue struct { - // elems holds a ring buffer. - // The queue is empty when begin = end. - // The queue is full (until grow is called) when end = begin + N - 1 (mod N) - // where N = cap(elems). - elems []any - head, len int -} - -func (q *queue) cap() int { - return len(q.elems) -} - -func (q *queue) grow() { - oldCap := q.cap() - newCap := oldCap * 2 - if newCap == 0 { - newCap = 8 - } - newElems := make([]any, newCap) - oldLen := q.len - for i := 0; i < oldLen; i++ { - newElems[i] = q.elems[(q.head+i)%oldCap] - } - q.elems = newElems - q.head = 0 -} - -func (q *queue) enqueue(e any) { - if q.len+1 > q.cap() { - q.grow() - } - i := (q.head + q.len) % q.cap() - q.elems[i] = e - q.len++ -} - -func (q *queue) dequeue() (any, bool) { - if q.len == 0 { - return nil, false - } - e := q.elems[q.head] - q.elems[q.head] = nil - q.head = (q.head + 1) % q.cap() - q.len-- - return e, true -} - -func (q *queue) peek() (any, bool) { - if q.len == 0 { - return nil, false - } - return q.elems[q.head], true -} - -func (q *queue) clear() { - *q = queue{} -} diff --git a/testing/internal/fuzz/queue_test.go b/testing/internal/fuzz/queue_test.go deleted file mode 100644 index 3b179afb..00000000 --- a/testing/internal/fuzz/queue_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2021 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 fuzz - -import "testing" - -func TestQueue(t *testing.T) { - // Zero valued queue should have 0 length and capacity. - var q queue - if n := q.len; n != 0 { - t.Fatalf("empty queue has len %d; want 0", n) - } - if n := q.cap(); n != 0 { - t.Fatalf("empty queue has cap %d; want 0", n) - } - - // As we add elements, len should grow. - N := 32 - for i := 0; i < N; i++ { - q.enqueue(i) - if n := q.len; n != i+1 { - t.Fatalf("after adding %d elements, queue has len %d", i, n) - } - if v, ok := q.peek(); !ok { - t.Fatalf("couldn't peek after adding %d elements", i) - } else if v.(int) != 0 { - t.Fatalf("after adding %d elements, peek is %d; want 0", i, v) - } - } - - // As we remove and add elements, len should shrink and grow. - // We should also remove elements in the same order they were added. - want := 0 - for _, r := range []int{1, 2, 3, 5, 8, 13, 21} { - s := make([]int, 0, r) - for i := 0; i < r; i++ { - if got, ok := q.dequeue(); !ok { - t.Fatalf("after removing %d of %d elements, could not dequeue", i+1, r) - } else if got != want { - t.Fatalf("after removing %d of %d elements, got %d; want %d", i+1, r, got, want) - } else { - s = append(s, got.(int)) - } - want = (want + 1) % N - if n := q.len; n != N-i-1 { - t.Fatalf("after removing %d of %d elements, len is %d; want %d", i+1, r, n, N-i-1) - } - } - for i, v := range s { - q.enqueue(v) - if n := q.len; n != N-r+i+1 { - t.Fatalf("after adding back %d of %d elements, len is %d; want %d", i+1, r, n, n-r+i+1) - } - } - } -} diff --git a/testing/internal/fuzz/sys_posix.go b/testing/internal/fuzz/sys_posix.go deleted file mode 100644 index 40d3771c..00000000 --- a/testing/internal/fuzz/sys_posix.go +++ /dev/null @@ -1,130 +0,0 @@ -// 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. - -//go:build darwin || freebsd || linux || openbsd - -package fuzz - -import ( - "fmt" - "os" - "os/exec" - "syscall" -) - -type sharedMemSys struct{} - -func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (*sharedMem, error) { - prot := syscall.PROT_READ | syscall.PROT_WRITE - flags := syscall.MAP_FILE | syscall.MAP_SHARED - region, err := syscall.Mmap(int(f.Fd()), 0, size, prot, flags) - if err != nil { - return nil, err - } - - return &sharedMem{f: f, region: region, removeOnClose: removeOnClose}, nil -} - -// Close unmaps the shared memory and closes the temporary file. If this -// sharedMem was created with sharedMemTempFile, Close also removes the file. -func (m *sharedMem) Close() error { - // Attempt all operations, even if we get an error for an earlier operation. - // os.File.Close may fail due to I/O errors, but we still want to delete - // the temporary file. - var errs []error - errs = append(errs, - syscall.Munmap(m.region), - m.f.Close()) - if m.removeOnClose { - errs = append(errs, os.Remove(m.f.Name())) - } - for _, err := range errs { - if err != nil { - return err - } - } - return nil -} - -// setWorkerComm configures communication channels on the cmd that will -// run a worker process. -func setWorkerComm(cmd *exec.Cmd, comm workerComm) { - mem := <-comm.memMu - memFile := mem.f - comm.memMu <- mem - cmd.ExtraFiles = []*os.File{comm.fuzzIn, comm.fuzzOut, memFile} -} - -// getWorkerComm returns communication channels in the worker process. -func getWorkerComm() (comm workerComm, err error) { - fuzzIn := os.NewFile(3, "fuzz_in") - fuzzOut := os.NewFile(4, "fuzz_out") - memFile := os.NewFile(5, "fuzz_mem") - fi, err := memFile.Stat() - if err != nil { - return workerComm{}, err - } - size := int(fi.Size()) - if int64(size) != fi.Size() { - return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size") - } - removeOnClose := false - mem, err := sharedMemMapFile(memFile, size, removeOnClose) - if err != nil { - return workerComm{}, err - } - memMu := make(chan *sharedMem, 1) - memMu <- mem - return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil -} - -// isInterruptError returns whether an error was returned by a process that -// was terminated by an interrupt signal (SIGINT). -func isInterruptError(err error) bool { - exitErr, ok := err.(*exec.ExitError) - if !ok || exitErr.ExitCode() >= 0 { - return false - } - status := exitErr.Sys().(syscall.WaitStatus) - return status.Signal() == syscall.SIGINT -} - -// terminationSignal checks if err is an exec.ExitError with a signal status. -// If it is, terminationSignal returns the signal and true. -// If not, -1 and false. -func terminationSignal(err error) (os.Signal, bool) { - exitErr, ok := err.(*exec.ExitError) - if !ok || exitErr.ExitCode() >= 0 { - return syscall.Signal(-1), false - } - status := exitErr.Sys().(syscall.WaitStatus) - return status.Signal(), status.Signaled() -} - -// isCrashSignal returns whether a signal was likely to have been caused by an -// error in the program that received it, triggered by a fuzz input. For -// example, SIGSEGV would be received after a nil pointer dereference. -// Other signals like SIGKILL or SIGHUP are more likely to have been sent by -// another process, and we shouldn't record a crasher if the worker process -// receives one of these. -// -// Note that Go installs its own signal handlers on startup, so some of these -// signals may only be received if signal handlers are changed. For example, -// SIGSEGV is normally transformed into a panic that causes the process to exit -// with status 2 if not recovered, which we handle as a crash. -func isCrashSignal(signal os.Signal) bool { - switch signal { - case - syscall.SIGILL, // illegal instruction - syscall.SIGTRAP, // breakpoint - syscall.SIGABRT, // abort() called - syscall.SIGBUS, // invalid memory access (e.g., misaligned address) - syscall.SIGFPE, // math error, e.g., integer divide by zero - syscall.SIGSEGV, // invalid memory access (e.g., write to read-only) - syscall.SIGPIPE: // sent data to closed pipe or socket - return true - default: - return false - } -} diff --git a/testing/internal/fuzz/sys_unimplemented.go b/testing/internal/fuzz/sys_unimplemented.go deleted file mode 100644 index 30766ba5..00000000 --- a/testing/internal/fuzz/sys_unimplemented.go +++ /dev/null @@ -1,44 +0,0 @@ -// 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. - -// If you update this constraint, also update internal/platform.FuzzSupported. -// -//go:build !darwin && !freebsd && !linux && !openbsd && !windows - -package fuzz - -import ( - "os" - "os/exec" -) - -type sharedMemSys struct{} - -func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (*sharedMem, error) { - panic("not implemented") -} - -func (m *sharedMem) Close() error { - panic("not implemented") -} - -func setWorkerComm(cmd *exec.Cmd, comm workerComm) { - panic("not implemented") -} - -func getWorkerComm() (comm workerComm, err error) { - panic("not implemented") -} - -func isInterruptError(err error) bool { - panic("not implemented") -} - -func terminationSignal(err error) (os.Signal, bool) { - panic("not implemented") -} - -func isCrashSignal(signal os.Signal) bool { - panic("not implemented") -} diff --git a/testing/internal/fuzz/sys_windows.go b/testing/internal/fuzz/sys_windows.go deleted file mode 100644 index 82c97034..00000000 --- a/testing/internal/fuzz/sys_windows.go +++ /dev/null @@ -1,144 +0,0 @@ -// 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 fuzz - -import ( - "fmt" - "os" - "os/exec" - "syscall" - "unsafe" -) - -type sharedMemSys struct { - mapObj syscall.Handle -} - -func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (mem *sharedMem, err error) { - defer func() { - if err != nil { - err = fmt.Errorf("mapping temporary file %s: %w", f.Name(), err) - } - }() - - // Create a file mapping object. The object itself is not shared. - mapObj, err := syscall.CreateFileMapping( - syscall.Handle(f.Fd()), // fhandle - nil, // sa - syscall.PAGE_READWRITE, // prot - 0, // maxSizeHigh - 0, // maxSizeLow - nil, // name - ) - if err != nil { - return nil, err - } - - // Create a view from the file mapping object. - access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE) - addr, err := syscall.MapViewOfFile( - mapObj, // handle - access, // access - 0, // offsetHigh - 0, // offsetLow - uintptr(size), // length - ) - if err != nil { - syscall.CloseHandle(mapObj) - return nil, err - } - - region := unsafe.Slice((*byte)(unsafe.Pointer(addr)), size) - return &sharedMem{ - f: f, - region: region, - removeOnClose: removeOnClose, - sys: sharedMemSys{mapObj: mapObj}, - }, nil -} - -// Close unmaps the shared memory and closes the temporary file. If this -// sharedMem was created with sharedMemTempFile, Close also removes the file. -func (m *sharedMem) Close() error { - // Attempt all operations, even if we get an error for an earlier operation. - // os.File.Close may fail due to I/O errors, but we still want to delete - // the temporary file. - var errs []error - errs = append(errs, - syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&m.region[0]))), - syscall.CloseHandle(m.sys.mapObj), - m.f.Close()) - if m.removeOnClose { - errs = append(errs, os.Remove(m.f.Name())) - } - for _, err := range errs { - if err != nil { - return err - } - } - return nil -} - -// setWorkerComm configures communication channels on the cmd that will -// run a worker process. -func setWorkerComm(cmd *exec.Cmd, comm workerComm) { - mem := <-comm.memMu - memFD := mem.f.Fd() - comm.memMu <- mem - syscall.SetHandleInformation(syscall.Handle(comm.fuzzIn.Fd()), syscall.HANDLE_FLAG_INHERIT, 1) - syscall.SetHandleInformation(syscall.Handle(comm.fuzzOut.Fd()), syscall.HANDLE_FLAG_INHERIT, 1) - syscall.SetHandleInformation(syscall.Handle(memFD), syscall.HANDLE_FLAG_INHERIT, 1) - cmd.Env = append(cmd.Env, fmt.Sprintf("GO_TEST_FUZZ_WORKER_HANDLES=%x,%x,%x", comm.fuzzIn.Fd(), comm.fuzzOut.Fd(), memFD)) - cmd.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(comm.fuzzIn.Fd()), syscall.Handle(comm.fuzzOut.Fd()), syscall.Handle(memFD)}} -} - -// getWorkerComm returns communication channels in the worker process. -func getWorkerComm() (comm workerComm, err error) { - v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES") - if v == "" { - return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set") - } - var fuzzInFD, fuzzOutFD, memFileFD uintptr - if _, err := fmt.Sscanf(v, "%x,%x,%x", &fuzzInFD, &fuzzOutFD, &memFileFD); err != nil { - return workerComm{}, fmt.Errorf("parsing GO_TEST_FUZZ_WORKER_HANDLES=%s: %v", v, err) - } - - fuzzIn := os.NewFile(fuzzInFD, "fuzz_in") - fuzzOut := os.NewFile(fuzzOutFD, "fuzz_out") - memFile := os.NewFile(memFileFD, "fuzz_mem") - fi, err := memFile.Stat() - if err != nil { - return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err) - } - size := int(fi.Size()) - if int64(size) != fi.Size() { - return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size") - } - removeOnClose := false - mem, err := sharedMemMapFile(memFile, size, removeOnClose) - if err != nil { - return workerComm{}, err - } - memMu := make(chan *sharedMem, 1) - memMu <- mem - - return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil -} - -func isInterruptError(err error) bool { - // On Windows, we can't tell whether the process was interrupted by the error - // returned by Wait. It looks like an ExitError with status 1. - return false -} - -// terminationSignal returns -1 and false because Windows doesn't have signals. -func terminationSignal(err error) (os.Signal, bool) { - return syscall.Signal(-1), false -} - -// isCrashSignal is not implemented because Windows doesn't have signals. -func isCrashSignal(signal os.Signal) bool { - panic("not implemented: no signals on windows") -} diff --git a/testing/internal/fuzz/trace.go b/testing/internal/fuzz/trace.go deleted file mode 100644 index a15c3700..00000000 --- a/testing/internal/fuzz/trace.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2021 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 !libfuzzer - -package fuzz - -import _ "unsafe" // for go:linkname - -//go:linkname libfuzzerTraceCmp1 runtime.libfuzzerTraceCmp1 -//go:linkname libfuzzerTraceCmp2 runtime.libfuzzerTraceCmp2 -//go:linkname libfuzzerTraceCmp4 runtime.libfuzzerTraceCmp4 -//go:linkname libfuzzerTraceCmp8 runtime.libfuzzerTraceCmp8 - -//go:linkname libfuzzerTraceConstCmp1 runtime.libfuzzerTraceConstCmp1 -//go:linkname libfuzzerTraceConstCmp2 runtime.libfuzzerTraceConstCmp2 -//go:linkname libfuzzerTraceConstCmp4 runtime.libfuzzerTraceConstCmp4 -//go:linkname libfuzzerTraceConstCmp8 runtime.libfuzzerTraceConstCmp8 - -//go:linkname libfuzzerHookStrCmp runtime.libfuzzerHookStrCmp -//go:linkname libfuzzerHookEqualFold runtime.libfuzzerHookEqualFold - -func libfuzzerTraceCmp1(arg0, arg1 uint8, fakePC uint) {} -func libfuzzerTraceCmp2(arg0, arg1 uint16, fakePC uint) {} -func libfuzzerTraceCmp4(arg0, arg1 uint32, fakePC uint) {} -func libfuzzerTraceCmp8(arg0, arg1 uint64, fakePC uint) {} - -func libfuzzerTraceConstCmp1(arg0, arg1 uint8, fakePC uint) {} -func libfuzzerTraceConstCmp2(arg0, arg1 uint16, fakePC uint) {} -func libfuzzerTraceConstCmp4(arg0, arg1 uint32, fakePC uint) {} -func libfuzzerTraceConstCmp8(arg0, arg1 uint64, fakePC uint) {} - -func libfuzzerHookStrCmp(arg0, arg1 string, fakePC uint) {} -func libfuzzerHookEqualFold(arg0, arg1 string, fakePC uint) {} diff --git a/testing/internal/fuzz/worker.go b/testing/internal/fuzz/worker.go deleted file mode 100644 index 9ee2f272..00000000 --- a/testing/internal/fuzz/worker.go +++ /dev/null @@ -1,1195 +0,0 @@ -// 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 fuzz - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/json" - "errors" - "fmt" - "io" - "os" - "os/exec" - "reflect" - "runtime" - "sync" - "time" -) - -const ( - // workerFuzzDuration is the amount of time a worker can spend testing random - // variations of an input given by the coordinator. - workerFuzzDuration = 100 * time.Millisecond - - // workerTimeoutDuration is the amount of time a worker can go without - // responding to the coordinator before being stopped. - workerTimeoutDuration = 1 * time.Second - - // workerExitCode is used as an exit code by fuzz worker processes after an internal error. - // This distinguishes internal errors from uncontrolled panics and other crashes. - // Keep in sync with internal/fuzz.workerExitCode. - workerExitCode = 70 - - // workerSharedMemSize is the maximum size of the shared memory file used to - // communicate with workers. This limits the size of fuzz inputs. - workerSharedMemSize = 100 << 20 // 100 MB -) - -// worker manages a worker process running a test binary. The worker object -// exists only in the coordinator (the process started by 'go test -fuzz'). -// workerClient is used by the coordinator to send RPCs to the worker process, -// which handles them with workerServer. -type worker struct { - dir string // working directory, same as package directory - binPath string // path to test executable - args []string // arguments for test executable - env []string // environment for test executable - - coordinator *coordinator - - memMu chan *sharedMem // mutex guarding shared memory with worker; persists across processes. - - cmd *exec.Cmd // current worker process - client *workerClient // used to communicate with worker process - waitErr error // last error returned by wait, set before termC is closed. - interrupted bool // true after stop interrupts a running worker. - termC chan struct{} // closed by wait when worker process terminates -} - -func newWorker(c *coordinator, dir, binPath string, args, env []string) (*worker, error) { - mem, err := sharedMemTempFile(workerSharedMemSize) - if err != nil { - return nil, err - } - memMu := make(chan *sharedMem, 1) - memMu <- mem - return &worker{ - dir: dir, - binPath: binPath, - args: args, - env: env[:len(env):len(env)], // copy on append to ensure workers don't overwrite each other. - coordinator: c, - memMu: memMu, - }, nil -} - -// cleanup releases persistent resources associated with the worker. -func (w *worker) cleanup() error { - mem := <-w.memMu - if mem == nil { - return nil - } - close(w.memMu) - return mem.Close() -} - -// coordinate runs the test binary to perform fuzzing. -// -// coordinate loops until ctx is canceled or a fatal error is encountered. -// If a test process terminates unexpectedly while fuzzing, coordinate will -// attempt to restart and continue unless the termination can be attributed -// to an interruption (from a timer or the user). -// -// While looping, coordinate receives inputs from the coordinator, passes -// those inputs to the worker process, then passes the results back to -// the coordinator. -func (w *worker) coordinate(ctx context.Context) error { - // Main event loop. - for { - // Start or restart the worker if it's not running. - if !w.isRunning() { - if err := w.startAndPing(ctx); err != nil { - return err - } - } - - select { - case <-ctx.Done(): - // Worker was told to stop. - err := w.stop() - if err != nil && !w.interrupted && !isInterruptError(err) { - return err - } - return ctx.Err() - - case <-w.termC: - // Worker process terminated unexpectedly while waiting for input. - err := w.stop() - if w.interrupted { - panic("worker interrupted after unexpected termination") - } - if err == nil || isInterruptError(err) { - // Worker stopped, either by exiting with status 0 or after being - // interrupted with a signal that was not sent by the coordinator. - // - // When the user presses ^C, on POSIX platforms, SIGINT is delivered to - // all processes in the group concurrently, and the worker may see it - // before the coordinator. The worker should exit 0 gracefully (in - // theory). - // - // This condition is probably intended by the user, so suppress - // the error. - return nil - } - if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == workerExitCode { - // Worker exited with a code indicating F.Fuzz was not called correctly, - // for example, F.Fail was called first. - return fmt.Errorf("fuzzing process exited unexpectedly due to an internal failure: %w", err) - } - // Worker exited non-zero or was terminated by a non-interrupt - // signal (for example, SIGSEGV) while fuzzing. - return fmt.Errorf("fuzzing process hung or terminated unexpectedly: %w", err) - // TODO(jayconrod,katiehockman): if -keepfuzzing, restart worker. - - case input := <-w.coordinator.inputC: - // Received input from coordinator. - args := fuzzArgs{ - Limit: input.limit, - Timeout: input.timeout, - Warmup: input.warmup, - CoverageData: input.coverageData, - } - entry, resp, isInternalError, err := w.client.fuzz(ctx, input.entry, args) - canMinimize := true - if err != nil { - // Error communicating with worker. - w.stop() - if ctx.Err() != nil { - // Timeout or interruption. - return ctx.Err() - } - if w.interrupted { - // Communication error before we stopped the worker. - // Report an error, but don't record a crasher. - return fmt.Errorf("communicating with fuzzing process: %v", err) - } - if sig, ok := terminationSignal(w.waitErr); ok && !isCrashSignal(sig) { - // Worker terminated by a signal that probably wasn't caused by a - // specific input to the fuzz function. For example, on Linux, - // the kernel (OOM killer) may send SIGKILL to a process using a lot - // of memory. Or the shell might send SIGHUP when the terminal - // is closed. Don't record a crasher. - return fmt.Errorf("fuzzing process terminated by unexpected signal; no crash will be recorded: %v", w.waitErr) - } - if isInternalError { - // An internal error occurred which shouldn't be considered - // a crash. - return err - } - // Unexpected termination. Set error message and fall through. - // We'll restart the worker on the next iteration. - // Don't attempt to minimize this since it crashed the worker. - resp.Err = fmt.Sprintf("fuzzing process hung or terminated unexpectedly: %v", w.waitErr) - canMinimize = false - } - result := fuzzResult{ - limit: input.limit, - count: resp.Count, - totalDuration: resp.TotalDuration, - entryDuration: resp.InterestingDuration, - entry: entry, - crasherMsg: resp.Err, - coverageData: resp.CoverageData, - canMinimize: canMinimize, - } - w.coordinator.resultC <- result - - case input := <-w.coordinator.minimizeC: - // Received input to minimize from coordinator. - result, err := w.minimize(ctx, input) - if err != nil { - // Error minimizing. Send back the original input. If it didn't cause - // an error before, report it as causing an error now. - // TODO: double-check this is handled correctly when - // implementing -keepfuzzing. - result = fuzzResult{ - entry: input.entry, - crasherMsg: input.crasherMsg, - canMinimize: false, - limit: input.limit, - } - if result.crasherMsg == "" { - result.crasherMsg = err.Error() - } - } - if shouldPrintDebugInfo() { - w.coordinator.debugLogf( - "input minimized, id: %s, original id: %s, crasher: %t, originally crasher: %t, minimizing took: %s", - result.entry.Path, - input.entry.Path, - result.crasherMsg != "", - input.crasherMsg != "", - result.totalDuration, - ) - } - w.coordinator.resultC <- result - } - } -} - -// minimize tells a worker process to attempt to find a smaller value that -// either causes an error (if we started minimizing because we found an input -// that causes an error) or preserves new coverage (if we started minimizing -// because we found an input that expands coverage). -func (w *worker) minimize(ctx context.Context, input fuzzMinimizeInput) (min fuzzResult, err error) { - if w.coordinator.opts.MinimizeTimeout != 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, w.coordinator.opts.MinimizeTimeout) - defer cancel() - } - - args := minimizeArgs{ - Limit: input.limit, - Timeout: input.timeout, - KeepCoverage: input.keepCoverage, - } - entry, resp, err := w.client.minimize(ctx, input.entry, args) - if err != nil { - // Error communicating with worker. - w.stop() - if ctx.Err() != nil || w.interrupted || isInterruptError(w.waitErr) { - // Worker was interrupted, possibly by the user pressing ^C. - // Normally, workers can handle interrupts and timeouts gracefully and - // will return without error. An error here indicates the worker - // may not have been in a good state, but the error won't be meaningful - // to the user. Just return the original crasher without logging anything. - return fuzzResult{ - entry: input.entry, - crasherMsg: input.crasherMsg, - coverageData: input.keepCoverage, - canMinimize: false, - limit: input.limit, - }, nil - } - return fuzzResult{ - entry: entry, - crasherMsg: fmt.Sprintf("fuzzing process hung or terminated unexpectedly while minimizing: %v", err), - canMinimize: false, - limit: input.limit, - count: resp.Count, - totalDuration: resp.Duration, - }, nil - } - - if input.crasherMsg != "" && resp.Err == "" { - return fuzzResult{}, fmt.Errorf("attempted to minimize a crash but could not reproduce") - } - - return fuzzResult{ - entry: entry, - crasherMsg: resp.Err, - coverageData: resp.CoverageData, - canMinimize: false, - limit: input.limit, - count: resp.Count, - totalDuration: resp.Duration, - }, nil -} - -func (w *worker) isRunning() bool { - return w.cmd != nil -} - -// startAndPing starts the worker process and sends it a message to make sure it -// can communicate. -// -// startAndPing returns an error if any part of this didn't work, including if -// the context is expired or the worker process was interrupted before it -// responded. Errors that happen after start but before the ping response -// likely indicate that the worker did not call F.Fuzz or called F.Fail first. -// We don't record crashers for these errors. -func (w *worker) startAndPing(ctx context.Context) error { - if ctx.Err() != nil { - return ctx.Err() - } - if err := w.start(); err != nil { - return err - } - if err := w.client.ping(ctx); err != nil { - w.stop() - if ctx.Err() != nil { - return ctx.Err() - } - if isInterruptError(err) { - // User may have pressed ^C before worker responded. - return err - } - // TODO: record and return stderr. - return fmt.Errorf("fuzzing process terminated without fuzzing: %w", err) - } - return nil -} - -// start runs a new worker process. -// -// If the process couldn't be started, start returns an error. Start won't -// return later termination errors from the process if they occur. -// -// If the process starts successfully, start returns nil. stop must be called -// once later to clean up, even if the process terminates on its own. -// -// When the process terminates, w.waitErr is set to the error (if any), and -// w.termC is closed. -func (w *worker) start() (err error) { - if w.isRunning() { - panic("worker already started") - } - w.waitErr = nil - w.interrupted = false - w.termC = nil - - cmd := exec.Command(w.binPath, w.args...) - cmd.Dir = w.dir - cmd.Env = w.env[:len(w.env):len(w.env)] // copy on append to ensure workers don't overwrite each other. - - // Create the "fuzz_in" and "fuzz_out" pipes so we can communicate with - // the worker. We don't use stdin and stdout, since the test binary may - // do something else with those. - // - // Each pipe has a reader and a writer. The coordinator writes to fuzzInW - // and reads from fuzzOutR. The worker inherits fuzzInR and fuzzOutW. - // The coordinator closes fuzzInR and fuzzOutW after starting the worker, - // since we have no further need of them. - fuzzInR, fuzzInW, err := os.Pipe() - if err != nil { - return err - } - defer fuzzInR.Close() - fuzzOutR, fuzzOutW, err := os.Pipe() - if err != nil { - fuzzInW.Close() - return err - } - defer fuzzOutW.Close() - setWorkerComm(cmd, workerComm{fuzzIn: fuzzInR, fuzzOut: fuzzOutW, memMu: w.memMu}) - - // Start the worker process. - if err := cmd.Start(); err != nil { - fuzzInW.Close() - fuzzOutR.Close() - return err - } - - // Worker started successfully. - // After this, w.client owns fuzzInW and fuzzOutR, so w.client.Close must be - // called later by stop. - w.cmd = cmd - w.termC = make(chan struct{}) - comm := workerComm{fuzzIn: fuzzInW, fuzzOut: fuzzOutR, memMu: w.memMu} - m := newMutator() - w.client = newWorkerClient(comm, m) - - go func() { - w.waitErr = w.cmd.Wait() - close(w.termC) - }() - - return nil -} - -// stop tells the worker process to exit by closing w.client, then blocks until -// it terminates. If the worker doesn't terminate after a short time, stop -// signals it with os.Interrupt (where supported), then os.Kill. -// -// stop returns the error the process terminated with, if any (same as -// w.waitErr). -// -// stop must be called at least once after start returns successfully, even if -// the worker process terminates unexpectedly. -func (w *worker) stop() error { - if w.termC == nil { - panic("worker was not started successfully") - } - select { - case <-w.termC: - // Worker already terminated. - if w.client == nil { - // stop already called. - return w.waitErr - } - // Possible unexpected termination. - w.client.Close() - w.cmd = nil - w.client = nil - return w.waitErr - default: - // Worker still running. - } - - // Tell the worker to stop by closing fuzz_in. It won't actually stop until it - // finishes with earlier calls. - closeC := make(chan struct{}) - go func() { - w.client.Close() - close(closeC) - }() - - sig := os.Interrupt - if runtime.GOOS == "windows" { - // Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on - // Windows; using it with os.Process.Signal will return an error.” - // Fall back to Kill instead. - sig = os.Kill - } - - t := time.NewTimer(workerTimeoutDuration) - for { - select { - case <-w.termC: - // Worker terminated. - t.Stop() - <-closeC - w.cmd = nil - w.client = nil - return w.waitErr - - case <-t.C: - // Timer fired before worker terminated. - w.interrupted = true - switch sig { - case os.Interrupt: - // Try to stop the worker with SIGINT and wait a little longer. - w.cmd.Process.Signal(sig) - sig = os.Kill - t.Reset(workerTimeoutDuration) - - case os.Kill: - // Try to stop the worker with SIGKILL and keep waiting. - w.cmd.Process.Signal(sig) - sig = nil - t.Reset(workerTimeoutDuration) - - case nil: - // Still waiting. Print a message to let the user know why. - fmt.Fprintf(w.coordinator.opts.Log, "waiting for fuzzing process to terminate...\n") - } - } - } -} - -// RunFuzzWorker is called in a worker process to communicate with the -// coordinator process in order to fuzz random inputs. RunFuzzWorker loops -// until the coordinator tells it to stop. -// -// fn is a wrapper on the fuzz function. It may return an error to indicate -// a given input "crashed". The coordinator will also record a crasher if -// the function times out or terminates the process. -// -// RunFuzzWorker returns an error if it could not communicate with the -// coordinator process. -func RunFuzzWorker(ctx context.Context, fn func(CorpusEntry) error) error { - comm, err := getWorkerComm() - if err != nil { - return err - } - srv := &workerServer{ - workerComm: comm, - fuzzFn: func(e CorpusEntry) (time.Duration, error) { - timer := time.AfterFunc(10*time.Second, func() { - panic("deadlocked!") // this error message won't be printed - }) - defer timer.Stop() - start := time.Now() - err := fn(e) - return time.Since(start), err - }, - m: newMutator(), - } - return srv.serve(ctx) -} - -// call is serialized and sent from the coordinator on fuzz_in. It acts as -// a minimalist RPC mechanism. Exactly one of its fields must be set to indicate -// which method to call. -type call struct { - Ping *pingArgs - Fuzz *fuzzArgs - Minimize *minimizeArgs -} - -// minimizeArgs contains arguments to workerServer.minimize. The value to -// minimize is already in shared memory. -type minimizeArgs struct { - // Timeout is the time to spend minimizing. This may include time to start up, - // especially if the input causes the worker process to terminated, requiring - // repeated restarts. - Timeout time.Duration - - // Limit is the maximum number of values to test, without spending more time - // than Duration. 0 indicates no limit. - Limit int64 - - // KeepCoverage is a set of coverage counters the worker should attempt to - // keep in minimized values. When provided, the worker will reject inputs that - // don't cause at least one of these bits to be set. - KeepCoverage []byte - - // Index is the index of the fuzz target parameter to be minimized. - Index int -} - -// minimizeResponse contains results from workerServer.minimize. -type minimizeResponse struct { - // WroteToMem is true if the worker found a smaller input and wrote it to - // shared memory. If minimizeArgs.KeepCoverage was set, the minimized input - // preserved at least one coverage bit and did not cause an error. - // Otherwise, the minimized input caused some error, recorded in Err. - WroteToMem bool - - // Err is the error string caused by the value in shared memory, if any. - Err string - - // CoverageData is the set of coverage bits activated by the minimized value - // in shared memory. When set, it contains at least one bit from KeepCoverage. - // CoverageData will be nil if Err is set or if minimization failed. - CoverageData []byte - - // Duration is the time spent minimizing, not including starting or cleaning up. - Duration time.Duration - - // Count is the number of values tested. - Count int64 -} - -// fuzzArgs contains arguments to workerServer.fuzz. The value to fuzz is -// passed in shared memory. -type fuzzArgs struct { - // Timeout is the time to spend fuzzing, not including starting or - // cleaning up. - Timeout time.Duration - - // Limit is the maximum number of values to test, without spending more time - // than Duration. 0 indicates no limit. - Limit int64 - - // Warmup indicates whether this is part of a warmup run, meaning that - // fuzzing should not occur. If coverageEnabled is true, then coverage data - // should be reported. - Warmup bool - - // CoverageData is the coverage data. If set, the worker should update its - // local coverage data prior to fuzzing. - CoverageData []byte -} - -// fuzzResponse contains results from workerServer.fuzz. -type fuzzResponse struct { - // Duration is the time spent fuzzing, not including starting or cleaning up. - TotalDuration time.Duration - InterestingDuration time.Duration - - // Count is the number of values tested. - Count int64 - - // CoverageData is set if the value in shared memory expands coverage - // and therefore may be interesting to the coordinator. - CoverageData []byte - - // Err is the error string caused by the value in shared memory, which is - // non-empty if the value in shared memory caused a crash. - Err string - - // InternalErr is the error string caused by an internal error in the - // worker. This shouldn't be considered a crasher. - InternalErr string -} - -// pingArgs contains arguments to workerServer.ping. -type pingArgs struct{} - -// pingResponse contains results from workerServer.ping. -type pingResponse struct{} - -// workerComm holds pipes and shared memory used for communication -// between the coordinator process (client) and a worker process (server). -// These values are unique to each worker; they are shared only with the -// coordinator, not with other workers. -// -// Access to shared memory is synchronized implicitly over the RPC protocol -// implemented in workerServer and workerClient. During a call, the client -// (worker) has exclusive access to shared memory; at other times, the server -// (coordinator) has exclusive access. -type workerComm struct { - fuzzIn, fuzzOut *os.File - memMu chan *sharedMem // mutex guarding shared memory -} - -// workerServer is a minimalist RPC server, run by fuzz worker processes. -// It allows the coordinator process (using workerClient) to call methods in a -// worker process. This system allows the coordinator to run multiple worker -// processes in parallel and to collect inputs that caused crashes from shared -// memory after a worker process terminates unexpectedly. -type workerServer struct { - workerComm - m *mutator - - // coverageMask is the local coverage data for the worker. It is - // periodically updated to reflect the data in the coordinator when new - // coverage is found. - coverageMask []byte - - // fuzzFn runs the worker's fuzz target on the given input and returns an - // error if it finds a crasher (the process may also exit or crash), and the - // time it took to run the input. It sets a deadline of 10 seconds, at which - // point it will panic with the assumption that the process is hanging or - // deadlocked. - fuzzFn func(CorpusEntry) (time.Duration, error) -} - -// serve reads serialized RPC messages on fuzzIn. When serve receives a message, -// it calls the corresponding method, then sends the serialized result back -// on fuzzOut. -// -// serve handles RPC calls synchronously; it will not attempt to read a message -// until the previous call has finished. -// -// serve returns errors that occurred when communicating over pipes. serve -// does not return errors from method calls; those are passed through serialized -// responses. -func (ws *workerServer) serve(ctx context.Context) error { - enc := json.NewEncoder(ws.fuzzOut) - dec := json.NewDecoder(&contextReader{ctx: ctx, r: ws.fuzzIn}) - for { - var c call - if err := dec.Decode(&c); err != nil { - if err == io.EOF || err == ctx.Err() { - return nil - } else { - return err - } - } - - var resp any - switch { - case c.Fuzz != nil: - resp = ws.fuzz(ctx, *c.Fuzz) - case c.Minimize != nil: - resp = ws.minimize(ctx, *c.Minimize) - case c.Ping != nil: - resp = ws.ping(ctx, *c.Ping) - default: - return errors.New("no arguments provided for any call") - } - - if err := enc.Encode(resp); err != nil { - return err - } - } -} - -// chainedMutations is how many mutations are applied before the worker -// resets the input to its original state. -// NOTE: this number was picked without much thought. It is low enough that -// it seems to create a significant diversity in mutated inputs. We may want -// to consider looking into this more closely once we have a proper performance -// testing framework. Another option is to randomly pick the number of chained -// mutations on each invocation of the workerServer.fuzz method (this appears to -// be what libFuzzer does, although there seems to be no documentation which -// explains why this choice was made.) -const chainedMutations = 5 - -// fuzz runs the test function on random variations of the input value in shared -// memory for a limited duration or number of iterations. -// -// fuzz returns early if it finds an input that crashes the fuzz function (with -// fuzzResponse.Err set) or an input that expands coverage (with -// fuzzResponse.InterestingDuration set). -// -// fuzz does not modify the input in shared memory. Instead, it saves the -// initial PRNG state in shared memory and increments a counter in shared -// memory before each call to the test function. The caller may reconstruct -// the crashing input with this information, since the PRNG is deterministic. -func (ws *workerServer) fuzz(ctx context.Context, args fuzzArgs) (resp fuzzResponse) { - if args.CoverageData != nil { - if ws.coverageMask != nil && len(args.CoverageData) != len(ws.coverageMask) { - resp.InternalErr = fmt.Sprintf("unexpected size for CoverageData: got %d, expected %d", len(args.CoverageData), len(ws.coverageMask)) - return resp - } - ws.coverageMask = args.CoverageData - } - start := time.Now() - defer func() { resp.TotalDuration = time.Since(start) }() - - if args.Timeout != 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, args.Timeout) - defer cancel() - } - mem := <-ws.memMu - ws.m.r.save(&mem.header().randState, &mem.header().randInc) - defer func() { - resp.Count = mem.header().count - ws.memMu <- mem - }() - if args.Limit > 0 && mem.header().count >= args.Limit { - resp.InternalErr = fmt.Sprintf("mem.header().count %d already exceeds args.Limit %d", mem.header().count, args.Limit) - return resp - } - - originalVals, err := unmarshalCorpusFile(mem.valueCopy()) - if err != nil { - resp.InternalErr = err.Error() - return resp - } - vals := make([]any, len(originalVals)) - copy(vals, originalVals) - - shouldStop := func() bool { - return args.Limit > 0 && mem.header().count >= args.Limit - } - fuzzOnce := func(entry CorpusEntry) (dur time.Duration, cov []byte, errMsg string) { - mem.header().count++ - var err error - dur, err = ws.fuzzFn(entry) - if err != nil { - errMsg = err.Error() - if errMsg == "" { - errMsg = "fuzz function failed with no input" - } - return dur, nil, errMsg - } - if ws.coverageMask != nil && countNewCoverageBits(ws.coverageMask, coverageSnapshot) > 0 { - return dur, coverageSnapshot, "" - } - return dur, nil, "" - } - - if args.Warmup { - dur, _, errMsg := fuzzOnce(CorpusEntry{Values: vals}) - if errMsg != "" { - resp.Err = errMsg - return resp - } - resp.InterestingDuration = dur - if coverageEnabled { - resp.CoverageData = coverageSnapshot - } - return resp - } - - for { - select { - case <-ctx.Done(): - return resp - default: - if mem.header().count%chainedMutations == 0 { - copy(vals, originalVals) - ws.m.r.save(&mem.header().randState, &mem.header().randInc) - } - ws.m.mutate(vals, cap(mem.valueRef())) - - entry := CorpusEntry{Values: vals} - dur, cov, errMsg := fuzzOnce(entry) - if errMsg != "" { - resp.Err = errMsg - return resp - } - if cov != nil { - resp.CoverageData = cov - resp.InterestingDuration = dur - return resp - } - if shouldStop() { - return resp - } - } - } -} - -func (ws *workerServer) minimize(ctx context.Context, args minimizeArgs) (resp minimizeResponse) { - start := time.Now() - defer func() { resp.Duration = time.Since(start) }() - mem := <-ws.memMu - defer func() { ws.memMu <- mem }() - vals, err := unmarshalCorpusFile(mem.valueCopy()) - if err != nil { - panic(err) - } - inpHash := sha256.Sum256(mem.valueCopy()) - if args.Timeout != 0 { - var cancel func() - ctx, cancel = context.WithTimeout(ctx, args.Timeout) - defer cancel() - } - - // Minimize the values in vals, then write to shared memory. We only write - // to shared memory after completing minimization. - success, err := ws.minimizeInput(ctx, vals, mem, args) - if success { - writeToMem(vals, mem) - outHash := sha256.Sum256(mem.valueCopy()) - mem.header().rawInMem = false - resp.WroteToMem = true - if err != nil { - resp.Err = err.Error() - } else { - // If the values didn't change during minimization then coverageSnapshot is likely - // a dirty snapshot which represents the very last step of minimization, not the - // coverage for the initial input. In that case just return the coverage we were - // given initially, since it more accurately represents the coverage map for the - // input we are returning. - if outHash != inpHash { - resp.CoverageData = coverageSnapshot - } else { - resp.CoverageData = args.KeepCoverage - } - } - } - return resp -} - -// minimizeInput applies a series of minimizing transformations on the provided -// vals, ensuring that each minimization still causes an error, or keeps -// coverage, in fuzzFn. It uses the context to determine how long to run, -// stopping once closed. It returns a bool indicating whether minimization was -// successful and an error if one was found. -func (ws *workerServer) minimizeInput(ctx context.Context, vals []any, mem *sharedMem, args minimizeArgs) (success bool, retErr error) { - keepCoverage := args.KeepCoverage - memBytes := mem.valueRef() - bPtr := &memBytes - count := &mem.header().count - shouldStop := func() bool { - return ctx.Err() != nil || - (args.Limit > 0 && *count >= args.Limit) - } - if shouldStop() { - return false, nil - } - - // Check that the original value preserves coverage or causes an error. - // If not, then whatever caused us to think the value was interesting may - // have been a flake, and we can't minimize it. - *count++ - _, retErr = ws.fuzzFn(CorpusEntry{Values: vals}) - if keepCoverage != nil { - if !hasCoverageBit(keepCoverage, coverageSnapshot) || retErr != nil { - return false, nil - } - } else if retErr == nil { - return false, nil - } - mem.header().rawInMem = true - - // tryMinimized runs the fuzz function with candidate replacing the value - // at index valI. tryMinimized returns whether the input with candidate is - // interesting for the same reason as the original input: it returns - // an error if one was expected, or it preserves coverage. - tryMinimized := func(candidate []byte) bool { - prev := vals[args.Index] - switch prev.(type) { - case []byte: - vals[args.Index] = candidate - case string: - vals[args.Index] = string(candidate) - default: - panic("impossible") - } - copy(*bPtr, candidate) - *bPtr = (*bPtr)[:len(candidate)] - mem.setValueLen(len(candidate)) - *count++ - _, err := ws.fuzzFn(CorpusEntry{Values: vals}) - if err != nil { - retErr = err - if keepCoverage != nil { - // Now that we've found a crash, that's more important than any - // minimization of interesting inputs that was being done. Clear out - // keepCoverage to only minimize the crash going forward. - keepCoverage = nil - } - return true - } - // Minimization should preserve coverage bits. - if keepCoverage != nil && isCoverageSubset(keepCoverage, coverageSnapshot) { - return true - } - vals[args.Index] = prev - return false - } - switch v := vals[args.Index].(type) { - case string: - minimizeBytes([]byte(v), tryMinimized, shouldStop) - case []byte: - minimizeBytes(v, tryMinimized, shouldStop) - default: - panic("impossible") - } - return true, retErr -} - -func writeToMem(vals []any, mem *sharedMem) { - b := marshalCorpusFile(vals...) - mem.setValue(b) -} - -// ping does nothing. The coordinator calls this method to ensure the worker -// has called F.Fuzz and can communicate. -func (ws *workerServer) ping(ctx context.Context, args pingArgs) pingResponse { - return pingResponse{} -} - -// workerClient is a minimalist RPC client. The coordinator process uses a -// workerClient to call methods in each worker process (handled by -// workerServer). -type workerClient struct { - workerComm - m *mutator - - // mu is the mutex protecting the workerComm.fuzzIn pipe. This must be - // locked before making calls to the workerServer. It prevents - // workerClient.Close from closing fuzzIn while workerClient methods are - // writing to it concurrently, and prevents multiple callers from writing to - // fuzzIn concurrently. - mu sync.Mutex -} - -func newWorkerClient(comm workerComm, m *mutator) *workerClient { - return &workerClient{workerComm: comm, m: m} -} - -// Close shuts down the connection to the RPC server (the worker process) by -// closing fuzz_in. Close drains fuzz_out (avoiding a SIGPIPE in the worker), -// and closes it after the worker process closes the other end. -func (wc *workerClient) Close() error { - wc.mu.Lock() - defer wc.mu.Unlock() - - // Close fuzzIn. This signals to the server that there are no more calls, - // and it should exit. - if err := wc.fuzzIn.Close(); err != nil { - wc.fuzzOut.Close() - return err - } - - // Drain fuzzOut and close it. When the server exits, the kernel will close - // its end of fuzzOut, and we'll get EOF. - if _, err := io.Copy(io.Discard, wc.fuzzOut); err != nil { - wc.fuzzOut.Close() - return err - } - return wc.fuzzOut.Close() -} - -// errSharedMemClosed is returned by workerClient methods that cannot access -// shared memory because it was closed and unmapped by another goroutine. That -// can happen when worker.cleanup is called in the worker goroutine while a -// workerClient.fuzz call runs concurrently. -// -// This error should not be reported. It indicates the operation was -// interrupted. -var errSharedMemClosed = errors.New("internal error: shared memory was closed and unmapped") - -// minimize tells the worker to call the minimize method. See -// workerServer.minimize. -func (wc *workerClient) minimize(ctx context.Context, entryIn CorpusEntry, args minimizeArgs) (entryOut CorpusEntry, resp minimizeResponse, retErr error) { - wc.mu.Lock() - defer wc.mu.Unlock() - - mem, ok := <-wc.memMu - if !ok { - return CorpusEntry{}, minimizeResponse{}, errSharedMemClosed - } - defer func() { wc.memMu <- mem }() - mem.header().count = 0 - inp, err := corpusEntryData(entryIn) - if err != nil { - return CorpusEntry{}, minimizeResponse{}, err - } - mem.setValue(inp) - entryOut = entryIn - entryOut.Values, err = unmarshalCorpusFile(inp) - if err != nil { - return CorpusEntry{}, minimizeResponse{}, fmt.Errorf("workerClient.minimize unmarshaling provided value: %v", err) - } - for i, v := range entryOut.Values { - if !isMinimizable(reflect.TypeOf(v)) { - continue - } - - wc.memMu <- mem - args.Index = i - c := call{Minimize: &args} - callErr := wc.callLocked(ctx, c, &resp) - mem, ok = <-wc.memMu - if !ok { - return CorpusEntry{}, minimizeResponse{}, errSharedMemClosed - } - - if callErr != nil { - retErr = callErr - if !mem.header().rawInMem { - // An unrecoverable error occurred before minimization began. - return entryIn, minimizeResponse{}, retErr - } - // An unrecoverable error occurred during minimization. mem now - // holds the raw, unmarshaled bytes of entryIn.Values[i] that - // caused the error. - switch entryOut.Values[i].(type) { - case string: - entryOut.Values[i] = string(mem.valueCopy()) - case []byte: - entryOut.Values[i] = mem.valueCopy() - default: - panic("impossible") - } - entryOut.Data = marshalCorpusFile(entryOut.Values...) - // Stop minimizing; another unrecoverable error is likely to occur. - break - } - - if resp.WroteToMem { - // Minimization succeeded, and mem holds the marshaled data. - entryOut.Data = mem.valueCopy() - entryOut.Values, err = unmarshalCorpusFile(entryOut.Data) - if err != nil { - return CorpusEntry{}, minimizeResponse{}, fmt.Errorf("workerClient.minimize unmarshaling minimized value: %v", err) - } - } - - // Prepare for next iteration of the loop. - if args.Timeout != 0 { - args.Timeout -= resp.Duration - if args.Timeout <= 0 { - break - } - } - if args.Limit != 0 { - args.Limit -= mem.header().count - if args.Limit <= 0 { - break - } - } - } - resp.Count = mem.header().count - h := sha256.Sum256(entryOut.Data) - entryOut.Path = fmt.Sprintf("%x", h[:4]) - return entryOut, resp, retErr -} - -// fuzz tells the worker to call the fuzz method. See workerServer.fuzz. -func (wc *workerClient) fuzz(ctx context.Context, entryIn CorpusEntry, args fuzzArgs) (entryOut CorpusEntry, resp fuzzResponse, isInternalError bool, err error) { - wc.mu.Lock() - defer wc.mu.Unlock() - - mem, ok := <-wc.memMu - if !ok { - return CorpusEntry{}, fuzzResponse{}, true, errSharedMemClosed - } - mem.header().count = 0 - inp, err := corpusEntryData(entryIn) - if err != nil { - wc.memMu <- mem - return CorpusEntry{}, fuzzResponse{}, true, err - } - mem.setValue(inp) - wc.memMu <- mem - - c := call{Fuzz: &args} - callErr := wc.callLocked(ctx, c, &resp) - if resp.InternalErr != "" { - return CorpusEntry{}, fuzzResponse{}, true, errors.New(resp.InternalErr) - } - mem, ok = <-wc.memMu - if !ok { - return CorpusEntry{}, fuzzResponse{}, true, errSharedMemClosed - } - defer func() { wc.memMu <- mem }() - resp.Count = mem.header().count - - if !bytes.Equal(inp, mem.valueRef()) { - return CorpusEntry{}, fuzzResponse{}, true, errors.New("workerServer.fuzz modified input") - } - needEntryOut := callErr != nil || resp.Err != "" || - (!args.Warmup && resp.CoverageData != nil) - if needEntryOut { - valuesOut, err := unmarshalCorpusFile(inp) - if err != nil { - return CorpusEntry{}, fuzzResponse{}, true, fmt.Errorf("unmarshaling fuzz input value after call: %v", err) - } - wc.m.r.restore(mem.header().randState, mem.header().randInc) - if !args.Warmup { - // Only mutate the valuesOut if fuzzing actually occurred. - numMutations := ((resp.Count - 1) % chainedMutations) + 1 - for i := int64(0); i < numMutations; i++ { - wc.m.mutate(valuesOut, cap(mem.valueRef())) - } - } - dataOut := marshalCorpusFile(valuesOut...) - - h := sha256.Sum256(dataOut) - name := fmt.Sprintf("%x", h[:4]) - entryOut = CorpusEntry{ - Parent: entryIn.Path, - Path: name, - Data: dataOut, - Generation: entryIn.Generation + 1, - } - if args.Warmup { - // The bytes weren't mutated, so if entryIn was a seed corpus value, - // then entryOut is too. - entryOut.IsSeed = entryIn.IsSeed - } - } - - return entryOut, resp, false, callErr -} - -// ping tells the worker to call the ping method. See workerServer.ping. -func (wc *workerClient) ping(ctx context.Context) error { - wc.mu.Lock() - defer wc.mu.Unlock() - c := call{Ping: &pingArgs{}} - var resp pingResponse - return wc.callLocked(ctx, c, &resp) -} - -// callLocked sends an RPC from the coordinator to the worker process and waits -// for the response. The callLocked may be canceled with ctx. -func (wc *workerClient) callLocked(ctx context.Context, c call, resp any) (err error) { - enc := json.NewEncoder(wc.fuzzIn) - dec := json.NewDecoder(&contextReader{ctx: ctx, r: wc.fuzzOut}) - if err := enc.Encode(c); err != nil { - return err - } - return dec.Decode(resp) -} - -// contextReader wraps a Reader with a Context. If the context is canceled -// while the underlying reader is blocked, Read returns immediately. -// -// This is useful for reading from a pipe. Closing a pipe file descriptor does -// not unblock pending Reads on that file descriptor. All copies of the pipe's -// other file descriptor (the write end) must be closed in all processes that -// inherit it. This is difficult to do correctly in the situation we care about -// (process group termination). -type contextReader struct { - ctx context.Context - r io.Reader -} - -func (cr *contextReader) Read(b []byte) (int, error) { - if ctxErr := cr.ctx.Err(); ctxErr != nil { - return 0, ctxErr - } - done := make(chan struct{}) - - // This goroutine may stay blocked after Read returns because the underlying - // read is blocked. - var n int - var err error - go func() { - n, err = cr.r.Read(b) - close(done) - }() - - select { - case <-cr.ctx.Done(): - return 0, cr.ctx.Err() - case <-done: - return n, err - } -} diff --git a/testing/internal/fuzz/worker_test.go b/testing/internal/fuzz/worker_test.go deleted file mode 100644 index a74aabf5..00000000 --- a/testing/internal/fuzz/worker_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2021 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 fuzz - -import ( - "context" - "errors" - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/race" - "io" - "os" - "os/signal" - "reflect" - "strconv" - "testing" - "time" -) - -var benchmarkWorkerFlag = flag.Bool("benchmarkworker", false, "") - -func TestMain(m *testing.M) { - flag.Parse() - if *benchmarkWorkerFlag { - runBenchmarkWorker() - return - } - os.Exit(m.Run()) -} - -func BenchmarkWorkerFuzzOverhead(b *testing.B) { - if race.Enabled { - b.Skip("TODO(48504): fix and re-enable") - } - origEnv := os.Getenv("GODEBUG") - defer func() { os.Setenv("GODEBUG", origEnv) }() - os.Setenv("GODEBUG", fmt.Sprintf("%s,fuzzseed=123", origEnv)) - - ws := &workerServer{ - fuzzFn: func(_ CorpusEntry) (time.Duration, error) { return time.Second, nil }, - workerComm: workerComm{memMu: make(chan *sharedMem, 1)}, - } - - mem, err := sharedMemTempFile(workerSharedMemSize) - if err != nil { - b.Fatalf("failed to create temporary shared memory file: %s", err) - } - defer func() { - if err := mem.Close(); err != nil { - b.Error(err) - } - }() - - initialVal := []any{make([]byte, 32)} - encodedVals := marshalCorpusFile(initialVal...) - mem.setValue(encodedVals) - - ws.memMu <- mem - - b.ResetTimer() - for i := 0; i < b.N; i++ { - ws.m = newMutator() - mem.setValue(encodedVals) - mem.header().count = 0 - - ws.fuzz(context.Background(), fuzzArgs{Limit: 1}) - } -} - -// BenchmarkWorkerPing acts as the coordinator and measures the time it takes -// a worker to respond to N pings. This is a rough measure of our RPC latency. -func BenchmarkWorkerPing(b *testing.B) { - if race.Enabled { - b.Skip("TODO(48504): fix and re-enable") - } - b.SetParallelism(1) - w := newWorkerForTest(b) - for i := 0; i < b.N; i++ { - if err := w.client.ping(context.Background()); err != nil { - b.Fatal(err) - } - } -} - -// BenchmarkWorkerFuzz acts as the coordinator and measures the time it takes -// a worker to mutate a given input and call a trivial fuzz function N times. -func BenchmarkWorkerFuzz(b *testing.B) { - if race.Enabled { - b.Skip("TODO(48504): fix and re-enable") - } - b.SetParallelism(1) - w := newWorkerForTest(b) - entry := CorpusEntry{Values: []any{[]byte(nil)}} - entry.Data = marshalCorpusFile(entry.Values...) - for i := int64(0); i < int64(b.N); { - args := fuzzArgs{ - Limit: int64(b.N) - i, - Timeout: workerFuzzDuration, - } - _, resp, _, err := w.client.fuzz(context.Background(), entry, args) - if err != nil { - b.Fatal(err) - } - if resp.Err != "" { - b.Fatal(resp.Err) - } - if resp.Count == 0 { - b.Fatal("worker did not make progress") - } - i += resp.Count - } -} - -// newWorkerForTest creates and starts a worker process for testing or -// benchmarking. The worker process calls RunFuzzWorker, which responds to -// RPC messages until it's stopped. The process is stopped and cleaned up -// automatically when the test is done. -func newWorkerForTest(tb testing.TB) *worker { - tb.Helper() - c, err := newCoordinator(CoordinateFuzzingOpts{ - Types: []reflect.Type{reflect.TypeOf([]byte(nil))}, - Log: io.Discard, - }) - if err != nil { - tb.Fatal(err) - } - dir := "" // same as self - binPath := os.Args[0] // same as self - args := append(os.Args[1:], "-benchmarkworker") - env := os.Environ() // same as self - w, err := newWorker(c, dir, binPath, args, env) - if err != nil { - tb.Fatal(err) - } - tb.Cleanup(func() { - if err := w.cleanup(); err != nil { - tb.Error(err) - } - }) - if err := w.startAndPing(context.Background()); err != nil { - tb.Fatal(err) - } - tb.Cleanup(func() { - if err := w.stop(); err != nil { - tb.Error(err) - } - }) - return w -} - -func runBenchmarkWorker() { - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - defer cancel() - fn := func(CorpusEntry) error { return nil } - if err := RunFuzzWorker(ctx, fn); err != nil && err != ctx.Err() { - panic(err) - } -} - -func BenchmarkWorkerMinimize(b *testing.B) { - if race.Enabled { - b.Skip("TODO(48504): fix and re-enable") - } - - ws := &workerServer{ - workerComm: workerComm{memMu: make(chan *sharedMem, 1)}, - } - - mem, err := sharedMemTempFile(workerSharedMemSize) - if err != nil { - b.Fatalf("failed to create temporary shared memory file: %s", err) - } - defer func() { - if err := mem.Close(); err != nil { - b.Error(err) - } - }() - ws.memMu <- mem - - bytes := make([]byte, 1024) - ctx := context.Background() - for sz := 1; sz <= len(bytes); sz <<= 1 { - sz := sz - input := []any{bytes[:sz]} - encodedVals := marshalCorpusFile(input...) - mem = <-ws.memMu - mem.setValue(encodedVals) - ws.memMu <- mem - b.Run(strconv.Itoa(sz), func(b *testing.B) { - i := 0 - ws.fuzzFn = func(_ CorpusEntry) (time.Duration, error) { - if i == 0 { - i++ - return time.Second, errors.New("initial failure for deflake") - } - return time.Second, nil - } - for i := 0; i < b.N; i++ { - b.SetBytes(int64(sz)) - ws.minimize(ctx, minimizeArgs{}) - } - }) - } -} diff --git a/testing/internal/goarch/gengoarch.go b/testing/internal/goarch/gengoarch.go deleted file mode 100644 index a52936ef..00000000 --- a/testing/internal/goarch/gengoarch.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2014 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 ignore - -package main - -import ( - "bytes" - "fmt" - "log" - "os" - "strings" -) - -var goarches []string - -func main() { - data, err := os.ReadFile("../../internal/syslist/syslist.go") - if err != nil { - log.Fatal(err) - } - const goarchPrefix = `var KnownArch = map[string]bool{` - inGOARCH := false - for _, line := range strings.Split(string(data), "\n") { - if strings.HasPrefix(line, goarchPrefix) { - inGOARCH = true - } else if inGOARCH && strings.HasPrefix(line, "}") { - break - } else if inGOARCH { - goarch := strings.Fields(line)[0] - goarch = strings.TrimPrefix(goarch, `"`) - goarch = strings.TrimSuffix(goarch, `":`) - goarches = append(goarches, goarch) - } - } - - for _, target := range goarches { - if target == "amd64p32" { - continue - } - var buf bytes.Buffer - fmt.Fprintf(&buf, "// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT.\n\n") - fmt.Fprintf(&buf, "//go:build %s\n\n", target) // must explicitly include target for bootstrapping purposes - fmt.Fprintf(&buf, "package goarch\n\n") - fmt.Fprintf(&buf, "const GOARCH = `%s`\n\n", target) - for _, goarch := range goarches { - value := 0 - if goarch == target { - value = 1 - } - fmt.Fprintf(&buf, "const Is%s = %d\n", strings.Title(goarch), value) - } - err := os.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666) - if err != nil { - log.Fatal(err) - } - } -} diff --git a/testing/internal/goarch/goarch.go b/testing/internal/goarch/goarch.go deleted file mode 100644 index f52fe6c4..00000000 --- a/testing/internal/goarch/goarch.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2021 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 goarch contains GOARCH-specific constants. -package goarch - -// The next line makes 'go generate' write the zgoarch*.go files with -// per-arch information, including constants named $GOARCH for every -// GOARCH. The constant is 1 on the current system, 0 otherwise; multiplying -// by them is useful for defining GOARCH-specific constants. -// -//go:generate go run gengoarch.go - -// ArchFamilyType represents a family of one or more related architectures. -// For example, ppc64 and ppc64le are both members of the PPC64 family. -type ArchFamilyType int - -const ( - AMD64 ArchFamilyType = iota - ARM - ARM64 - I386 - LOONG64 - MIPS - MIPS64 - PPC64 - RISCV64 - S390X - WASM -) - -// PtrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant. -// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit). -const PtrSize = 4 << (^uintptr(0) >> 63) - -// ArchFamily is the architecture family (AMD64, ARM, ...) -const ArchFamily ArchFamilyType = _ArchFamily - -// BigEndian reports whether the architecture is big-endian. -const BigEndian = IsArmbe|IsArm64be|IsMips|IsMips64|IsPpc|IsPpc64|IsS390|IsS390x|IsSparc|IsSparc64 == 1 - -// DefaultPhysPageSize is the default physical page size. -const DefaultPhysPageSize = _DefaultPhysPageSize - -// PCQuantum is the minimal unit for a program counter (1 on x86, 4 on most other systems). -// The various PC tables record PC deltas pre-divided by PCQuantum. -const PCQuantum = _PCQuantum - -// Int64Align is the required alignment for a 64-bit integer (4 on 32-bit systems, 8 on 64-bit). -const Int64Align = PtrSize - -// MinFrameSize is the size of the system-reserved words at the bottom -// of a frame (just above the architectural stack pointer). -// It is zero on x86 and PtrSize on most non-x86 (LR-based) systems. -// On PowerPC it is larger, to cover three more reserved words: -// the compiler word, the link editor word, and the TOC save word. -const MinFrameSize = _MinFrameSize - -// StackAlign is the required alignment of the SP register. -// The stack must be at least word aligned, but some architectures require more. -const StackAlign = _StackAlign diff --git a/testing/internal/goarch/goarch_386.go b/testing/internal/goarch/goarch_386.go deleted file mode 100644 index c6214217..00000000 --- a/testing/internal/goarch/goarch_386.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = I386 - _DefaultPhysPageSize = 4096 - _PCQuantum = 1 - _MinFrameSize = 0 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_amd64.go b/testing/internal/goarch/goarch_amd64.go deleted file mode 100644 index 911e3e72..00000000 --- a/testing/internal/goarch/goarch_amd64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = AMD64 - _DefaultPhysPageSize = 4096 - _PCQuantum = 1 - _MinFrameSize = 0 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_arm.go b/testing/internal/goarch/goarch_arm.go deleted file mode 100644 index a6591713..00000000 --- a/testing/internal/goarch/goarch_arm.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = ARM - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 4 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_arm64.go b/testing/internal/goarch/goarch_arm64.go deleted file mode 100644 index 85d0b476..00000000 --- a/testing/internal/goarch/goarch_arm64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = ARM64 - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 8 - _StackAlign = 16 -) diff --git a/testing/internal/goarch/goarch_loong64.go b/testing/internal/goarch/goarch_loong64.go deleted file mode 100644 index dae1f4da..00000000 --- a/testing/internal/goarch/goarch_loong64.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022 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 loong64 - -package goarch - -const ( - _ArchFamily = LOONG64 - _DefaultPhysPageSize = 16384 - _PCQuantum = 4 - _MinFrameSize = 8 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_mips.go b/testing/internal/goarch/goarch_mips.go deleted file mode 100644 index 59f3995e..00000000 --- a/testing/internal/goarch/goarch_mips.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = MIPS - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 4 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_mips64.go b/testing/internal/goarch/goarch_mips64.go deleted file mode 100644 index 9e4f8279..00000000 --- a/testing/internal/goarch/goarch_mips64.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = MIPS64 - _DefaultPhysPageSize = 16384 - _PCQuantum = 4 - _MinFrameSize = 8 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_mips64le.go b/testing/internal/goarch/goarch_mips64le.go deleted file mode 100644 index 9e4f8279..00000000 --- a/testing/internal/goarch/goarch_mips64le.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = MIPS64 - _DefaultPhysPageSize = 16384 - _PCQuantum = 4 - _MinFrameSize = 8 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_mipsle.go b/testing/internal/goarch/goarch_mipsle.go deleted file mode 100644 index 3e6642bb..00000000 --- a/testing/internal/goarch/goarch_mipsle.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = MIPS - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 4 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_ppc64.go b/testing/internal/goarch/goarch_ppc64.go deleted file mode 100644 index 60cc846e..00000000 --- a/testing/internal/goarch/goarch_ppc64.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = PPC64 - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 32 - _StackAlign = 16 -) diff --git a/testing/internal/goarch/goarch_ppc64le.go b/testing/internal/goarch/goarch_ppc64le.go deleted file mode 100644 index 60cc846e..00000000 --- a/testing/internal/goarch/goarch_ppc64le.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 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 goarch - -const ( - _ArchFamily = PPC64 - _DefaultPhysPageSize = 65536 - _PCQuantum = 4 - _MinFrameSize = 32 - _StackAlign = 16 -) diff --git a/testing/internal/goarch/goarch_riscv64.go b/testing/internal/goarch/goarch_riscv64.go deleted file mode 100644 index 3b6da1e0..00000000 --- a/testing/internal/goarch/goarch_riscv64.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = RISCV64 - _DefaultPhysPageSize = 4096 - _PCQuantum = 4 - _MinFrameSize = 8 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_s390x.go b/testing/internal/goarch/goarch_s390x.go deleted file mode 100644 index 20c57055..00000000 --- a/testing/internal/goarch/goarch_s390x.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 goarch - -const ( - _ArchFamily = S390X - _DefaultPhysPageSize = 4096 - _PCQuantum = 2 - _MinFrameSize = 8 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/goarch_wasm.go b/testing/internal/goarch/goarch_wasm.go deleted file mode 100644 index 98618d69..00000000 --- a/testing/internal/goarch/goarch_wasm.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2018 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 goarch - -const ( - _ArchFamily = WASM - _DefaultPhysPageSize = 65536 - _PCQuantum = 1 - _MinFrameSize = 0 - _StackAlign = PtrSize -) diff --git a/testing/internal/goarch/zgoarch_386.go b/testing/internal/goarch/zgoarch_386.go deleted file mode 100644 index 4a9b0e67..00000000 --- a/testing/internal/goarch/zgoarch_386.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build 386 - -package goarch - -const GOARCH = `386` - -const Is386 = 1 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_amd64.go b/testing/internal/goarch/zgoarch_amd64.go deleted file mode 100644 index 7926392b..00000000 --- a/testing/internal/goarch/zgoarch_amd64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build amd64 - -package goarch - -const GOARCH = `amd64` - -const Is386 = 0 -const IsAmd64 = 1 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_arm.go b/testing/internal/goarch/zgoarch_arm.go deleted file mode 100644 index 6c03b8b0..00000000 --- a/testing/internal/goarch/zgoarch_arm.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build arm - -package goarch - -const GOARCH = `arm` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 1 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_arm64.go b/testing/internal/goarch/zgoarch_arm64.go deleted file mode 100644 index ad342d79..00000000 --- a/testing/internal/goarch/zgoarch_arm64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build arm64 - -package goarch - -const GOARCH = `arm64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 1 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_arm64be.go b/testing/internal/goarch/zgoarch_arm64be.go deleted file mode 100644 index 0f260030..00000000 --- a/testing/internal/goarch/zgoarch_arm64be.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build arm64be - -package goarch - -const GOARCH = `arm64be` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 1 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_armbe.go b/testing/internal/goarch/zgoarch_armbe.go deleted file mode 100644 index 6092fee7..00000000 --- a/testing/internal/goarch/zgoarch_armbe.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build armbe - -package goarch - -const GOARCH = `armbe` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 1 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_loong64.go b/testing/internal/goarch/zgoarch_loong64.go deleted file mode 100644 index 21c67e11..00000000 --- a/testing/internal/goarch/zgoarch_loong64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build loong64 - -package goarch - -const GOARCH = `loong64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 1 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mips.go b/testing/internal/goarch/zgoarch_mips.go deleted file mode 100644 index 0db19746..00000000 --- a/testing/internal/goarch/zgoarch_mips.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mips - -package goarch - -const GOARCH = `mips` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 1 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mips64.go b/testing/internal/goarch/zgoarch_mips64.go deleted file mode 100644 index 738806f0..00000000 --- a/testing/internal/goarch/zgoarch_mips64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mips64 - -package goarch - -const GOARCH = `mips64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 1 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mips64le.go b/testing/internal/goarch/zgoarch_mips64le.go deleted file mode 100644 index 8de5beb8..00000000 --- a/testing/internal/goarch/zgoarch_mips64le.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mips64le - -package goarch - -const GOARCH = `mips64le` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 1 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mips64p32.go b/testing/internal/goarch/zgoarch_mips64p32.go deleted file mode 100644 index ea461bed..00000000 --- a/testing/internal/goarch/zgoarch_mips64p32.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mips64p32 - -package goarch - -const GOARCH = `mips64p32` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 1 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mips64p32le.go b/testing/internal/goarch/zgoarch_mips64p32le.go deleted file mode 100644 index 15473ce6..00000000 --- a/testing/internal/goarch/zgoarch_mips64p32le.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mips64p32le - -package goarch - -const GOARCH = `mips64p32le` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 1 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_mipsle.go b/testing/internal/goarch/zgoarch_mipsle.go deleted file mode 100644 index 4955142e..00000000 --- a/testing/internal/goarch/zgoarch_mipsle.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build mipsle - -package goarch - -const GOARCH = `mipsle` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 1 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_ppc.go b/testing/internal/goarch/zgoarch_ppc.go deleted file mode 100644 index ec01763b..00000000 --- a/testing/internal/goarch/zgoarch_ppc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build ppc - -package goarch - -const GOARCH = `ppc` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 1 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_ppc64.go b/testing/internal/goarch/zgoarch_ppc64.go deleted file mode 100644 index 39be3925..00000000 --- a/testing/internal/goarch/zgoarch_ppc64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build ppc64 - -package goarch - -const GOARCH = `ppc64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 1 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_ppc64le.go b/testing/internal/goarch/zgoarch_ppc64le.go deleted file mode 100644 index 5f959e0e..00000000 --- a/testing/internal/goarch/zgoarch_ppc64le.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build ppc64le - -package goarch - -const GOARCH = `ppc64le` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 1 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_riscv.go b/testing/internal/goarch/zgoarch_riscv.go deleted file mode 100644 index 8d81a14d..00000000 --- a/testing/internal/goarch/zgoarch_riscv.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build riscv - -package goarch - -const GOARCH = `riscv` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 1 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_riscv64.go b/testing/internal/goarch/zgoarch_riscv64.go deleted file mode 100644 index 1df989c2..00000000 --- a/testing/internal/goarch/zgoarch_riscv64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build riscv64 - -package goarch - -const GOARCH = `riscv64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 1 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_s390.go b/testing/internal/goarch/zgoarch_s390.go deleted file mode 100644 index 56815b9f..00000000 --- a/testing/internal/goarch/zgoarch_s390.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build s390 - -package goarch - -const GOARCH = `s390` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 1 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_s390x.go b/testing/internal/goarch/zgoarch_s390x.go deleted file mode 100644 index e61e9bd5..00000000 --- a/testing/internal/goarch/zgoarch_s390x.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build s390x - -package goarch - -const GOARCH = `s390x` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 1 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_sparc.go b/testing/internal/goarch/zgoarch_sparc.go deleted file mode 100644 index ee5b7465..00000000 --- a/testing/internal/goarch/zgoarch_sparc.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build sparc - -package goarch - -const GOARCH = `sparc` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 1 -const IsSparc64 = 0 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_sparc64.go b/testing/internal/goarch/zgoarch_sparc64.go deleted file mode 100644 index 519aaa10..00000000 --- a/testing/internal/goarch/zgoarch_sparc64.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build sparc64 - -package goarch - -const GOARCH = `sparc64` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 1 -const IsWasm = 0 diff --git a/testing/internal/goarch/zgoarch_wasm.go b/testing/internal/goarch/zgoarch_wasm.go deleted file mode 100644 index 25567a1b..00000000 --- a/testing/internal/goarch/zgoarch_wasm.go +++ /dev/null @@ -1,32 +0,0 @@ -// Code generated by gengoarch.go using 'go generate'. DO NOT EDIT. - -//go:build wasm - -package goarch - -const GOARCH = `wasm` - -const Is386 = 0 -const IsAmd64 = 0 -const IsAmd64p32 = 0 -const IsArm = 0 -const IsArmbe = 0 -const IsArm64 = 0 -const IsArm64be = 0 -const IsLoong64 = 0 -const IsMips = 0 -const IsMipsle = 0 -const IsMips64 = 0 -const IsMips64le = 0 -const IsMips64p32 = 0 -const IsMips64p32le = 0 -const IsPpc = 0 -const IsPpc64 = 0 -const IsPpc64le = 0 -const IsRiscv = 0 -const IsRiscv64 = 0 -const IsS390 = 0 -const IsS390x = 0 -const IsSparc = 0 -const IsSparc64 = 0 -const IsWasm = 1 diff --git a/testing/internal/godebug/godebug.go b/testing/internal/godebug/godebug.go deleted file mode 100644 index 24c60fed..00000000 --- a/testing/internal/godebug/godebug.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2021 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 godebug makes the settings in the $GODEBUG environment variable -// available to other packages. These settings are often used for compatibility -// tweaks, when we need to change a default behavior but want to let users -// opt back in to the original. For example GODEBUG=http2server=0 disables -// HTTP/2 support in the net/http server. -// -// In typical usage, code should declare a Setting as a global -// and then call Value each time the current setting value is needed: -// -// var http2server = godebug.New("http2server") -// -// func ServeConn(c net.Conn) { -// if http2server.Value() == "0" { -// disallow HTTP/2 -// ... -// } -// ... -// } -// -// Each time a non-default setting causes a change in program behavior, -// code must call [Setting.IncNonDefault] to increment a counter that can -// be reported by [runtime/metrics.Read]. The call must only happen when -// the program executes a non-default behavior, not just when the setting -// is set to a non-default value. This is occasionally (but very rarely) -// infeasible, in which case the internal/godebugs table entry must set -// Opaque: true, and the documentation in doc/godebug.md should -// mention that metrics are unavailable. -// -// Conventionally, the global variable representing a godebug is named -// for the godebug itself, with no case changes: -// -// var gotypesalias = godebug.New("gotypesalias") // this -// var goTypesAlias = godebug.New("gotypesalias") // NOT THIS -// -// The test in internal/godebugs that checks for use of IncNonDefault -// requires the use of this convention. -// -// Note that counters used with IncNonDefault must be added to -// various tables in other packages. See the [Setting.IncNonDefault] -// documentation for details. -package godebug - -// Note: Be careful about new imports here. Any package -// that internal/godebug imports cannot itself import internal/godebug, -// meaning it cannot introduce a GODEBUG setting of its own. -// We keep imports to the absolute bare minimum. -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/bisect" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebugs" - "sync" - "sync/atomic" - "unsafe" - _ "unsafe" // go:linkname -) - -// A Setting is a single setting in the $GODEBUG environment variable. -type Setting struct { - name string - once sync.Once - *setting -} - -type setting struct { - value atomic.Pointer[value] - nonDefaultOnce sync.Once - nonDefault atomic.Uint64 - info *godebugs.Info -} - -type value struct { - text string - bisect *bisect.Matcher -} - -// New returns a new Setting for the $GODEBUG setting with the given name. -// -// GODEBUGs meant for use by end users must be listed in ../godebugs/table.go, -// which is used for generating and checking various documentation. -// If the name is not listed in that table, New will succeed but calling Value -// on the returned Setting will panic. -// To disable that panic for access to an undocumented setting, -// prefix the name with a #, as in godebug.New("#gofsystrace"). -// The # is a signal to New but not part of the key used in $GODEBUG. -// -// Note that almost all settings should arrange to call [IncNonDefault] precisely -// when program behavior is changing from the default due to the setting -// (not just when the setting is different, but when program behavior changes). -// See the [internal/godebug] package comment for more. -func New(name string) *Setting { - return &Setting{name: name} -} - -// Name returns the name of the setting. -func (s *Setting) Name() string { - if s.name != "" && s.name[0] == '#' { - return s.name[1:] - } - return s.name -} - -// Undocumented reports whether this is an undocumented setting. -func (s *Setting) Undocumented() bool { - return s.name != "" && s.name[0] == '#' -} - -// String returns a printable form for the setting: name=value. -func (s *Setting) String() string { - return s.Name() + "=" + s.Value() -} - -// IncNonDefault increments the non-default behavior counter -// associated with the given setting. -// This counter is exposed in the runtime/metrics value -// /godebug/non-default-behavior/:events. -// -// Note that Value must be called at least once before IncNonDefault. -func (s *Setting) IncNonDefault() { - s.nonDefaultOnce.Do(s.register) - s.nonDefault.Add(1) -} - -func (s *Setting) register() { - if s.info == nil || s.info.Opaque { - panic("godebug: unexpected IncNonDefault of " + s.name) - } - registerMetric("/godebug/non-default-behavior/"+s.Name()+":events", s.nonDefault.Load) -} - -// cache is a cache of all the GODEBUG settings, -// a locked map[string]*atomic.Pointer[string]. -// -// All Settings with the same name share a single -// *atomic.Pointer[string], so that when GODEBUG -// changes only that single atomic string pointer -// needs to be updated. -// -// A name appears in the values map either if it is the -// name of a Setting for which Value has been called -// at least once, or if the name has ever appeared in -// a name=value pair in the $GODEBUG environment variable. -// Once entered into the map, the name is never removed. -var cache sync.Map // name string -> value *atomic.Pointer[string] - -var empty value - -// Value returns the current value for the GODEBUG setting s. -// -// Value maintains an internal cache that is synchronized -// with changes to the $GODEBUG environment variable, -// making Value efficient to call as frequently as needed. -// Clients should therefore typically not attempt their own -// caching of Value's result. -func (s *Setting) Value() string { - s.once.Do(func() { - s.setting = lookup(s.Name()) - if s.info == nil && !s.Undocumented() { - panic("godebug: Value of name not listed in godebugs.All: " + s.name) - } - }) - v := *s.value.Load() - if v.bisect != nil && !v.bisect.Stack(&stderr) { - return "" - } - return v.text -} - -// lookup returns the unique *setting value for the given name. -func lookup(name string) *setting { - if v, ok := cache.Load(name); ok { - return v.(*setting) - } - s := new(setting) - s.info = godebugs.Lookup(name) - s.value.Store(&empty) - if v, loaded := cache.LoadOrStore(name, s); loaded { - // Lost race: someone else created it. Use theirs. - return v.(*setting) - } - - return s -} - -// setUpdate is provided by package runtime. -// It calls update(def, env), where def is the default GODEBUG setting -// and env is the current value of the $GODEBUG environment variable. -// After that first call, the runtime calls update(def, env) -// again each time the environment variable changes -// (due to use of os.Setenv, for example). -// -//go:linkname setUpdate -func setUpdate(update func(string, string)) - -// registerMetric is provided by package runtime. -// It forwards registrations to runtime/metrics. -// -//go:linkname registerMetric -func registerMetric(name string, read func() uint64) - -// setNewIncNonDefault is provided by package runtime. -// The runtime can do -// -// inc := newNonDefaultInc(name) -// -// instead of -// -// inc := godebug.New(name).IncNonDefault -// -// since it cannot import godebug. -// -//go:linkname setNewIncNonDefault -func setNewIncNonDefault(newIncNonDefault func(string) func()) - -func init() { - setUpdate(update) - setNewIncNonDefault(newIncNonDefault) -} - -func newIncNonDefault(name string) func() { - s := New(name) - s.Value() - return s.IncNonDefault -} - -var updateMu sync.Mutex - -// update records an updated GODEBUG setting. -// def is the default GODEBUG setting for the running binary, -// and env is the current value of the $GODEBUG environment variable. -func update(def, env string) { - updateMu.Lock() - defer updateMu.Unlock() - - // Update all the cached values, creating new ones as needed. - // We parse the environment variable first, so that any settings it has - // are already locked in place (did[name] = true) before we consider - // the defaults. Existing immutable settings are always locked. - did := make(map[string]bool) - cache.Range(func(name, s any) bool { - if info := s.(*setting).info; info != nil && info.Immutable { - did[name.(string)] = true - } - return true - }) - parse(did, env) - parse(did, def) - - // Clear any cached values that are no longer present. - cache.Range(func(name, s any) bool { - if !did[name.(string)] { - s.(*setting).value.Store(&empty) - } - return true - }) -} - -// parse parses the GODEBUG setting string s, -// which has the form k=v,k2=v2,k3=v3. -// Later settings override earlier ones. -// Parse only updates settings k=v for which did[k] = false. -// It also sets did[k] = true for settings that it updates. -// Each value v can also have the form v#pattern, -// in which case the GODEBUG is only enabled for call stacks -// matching pattern, for use with golang.org/x/tools/cmd/bisect. -func parse(did map[string]bool, s string) { - // Scan the string backward so that later settings are used - // and earlier settings are ignored. - // Note that a forward scan would cause cached values - // to temporarily use the ignored value before being - // updated to the "correct" one. - end := len(s) - eq := -1 - for i := end - 1; i >= -1; i-- { - if i == -1 || s[i] == ',' { - if eq >= 0 { - name, arg := s[i+1:eq], s[eq+1:end] - if !did[name] { - did[name] = true - v := &value{text: arg} - for j := 0; j < len(arg); j++ { - if arg[j] == '#' { - v.text = arg[:j] - v.bisect, _ = bisect.New(arg[j+1:]) - break - } - } - lookup(name).value.Store(v) - } - } - eq = -1 - end = i - } else if s[i] == '=' { - eq = i - } - } -} - -type runtimeStderr struct{} - -var stderr runtimeStderr - -func (*runtimeStderr) Write(b []byte) (int, error) { - if len(b) > 0 { - write(2, unsafe.Pointer(&b[0]), int32(len(b))) - } - return len(b), nil -} - -// Since we cannot import os or syscall, use the runtime's write function -// to print to standard error. -// -//go:linkname write runtime.write -func write(fd uintptr, p unsafe.Pointer, n int32) int32 diff --git a/testing/internal/godebug/godebug_test.go b/testing/internal/godebug/godebug_test.go deleted file mode 100644 index 2b9f7181..00000000 --- a/testing/internal/godebug/godebug_test.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2021 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 godebug_test - -import ( - "fmt" - . "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebug" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/race" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "runtime/metrics" - "slices" - "strings" - "testing" -) - -func TestGet(t *testing.T) { - foo := New("#foo") - tests := []struct { - godebug string - setting *Setting - want string - }{ - {"", New("#"), ""}, - {"", foo, ""}, - {"foo=bar", foo, "bar"}, - {"foo=bar,after=x", foo, "bar"}, - {"before=x,foo=bar,after=x", foo, "bar"}, - {"before=x,foo=bar", foo, "bar"}, - {",,,foo=bar,,,", foo, "bar"}, - {"foodecoy=wrong,foo=bar", foo, "bar"}, - {"foo=", foo, ""}, - {"foo", foo, ""}, - {",foo", foo, ""}, - {"foo=bar,baz", New("#loooooooong"), ""}, - } - for _, tt := range tests { - t.Setenv("GODEBUG", tt.godebug) - got := tt.setting.Value() - if got != tt.want { - t.Errorf("get(%q, %q) = %q; want %q", tt.godebug, tt.setting.Name(), got, tt.want) - } - } -} - -func TestMetrics(t *testing.T) { - const name = "http2client" // must be a real name so runtime will accept it - - var m [1]metrics.Sample - m[0].Name = "/godebug/non-default-behavior/" + name + ":events" - metrics.Read(m[:]) - if kind := m[0].Value.Kind(); kind != metrics.KindUint64 { - t.Fatalf("NonDefault kind = %v, want uint64", kind) - } - - s := New(name) - s.Value() - s.IncNonDefault() - s.IncNonDefault() - s.IncNonDefault() - metrics.Read(m[:]) - if kind := m[0].Value.Kind(); kind != metrics.KindUint64 { - t.Fatalf("NonDefault kind = %v, want uint64", kind) - } - if count := m[0].Value.Uint64(); count != 3 { - t.Fatalf("NonDefault value = %d, want 3", count) - } -} - -// TestPanicNilRace checks for a race in the runtime caused by use of runtime -// atomics (not visible to usual race detection) to install the counter for -// non-default panic(nil) semantics. For #64649. -func TestPanicNilRace(t *testing.T) { - if !race.Enabled { - t.Skip("Skipping test intended for use with -race.") - } - if os.Getenv("GODEBUG") != "panicnil=1" { - cmd := testenv.CleanCmdEnv(testenv.Command(t, testenv.Executable(t), "-test.run=^TestPanicNilRace$", "-test.v", "-test.parallel=2", "-test.count=1")) - cmd.Env = append(cmd.Env, "GODEBUG=panicnil=1") - out, err := cmd.CombinedOutput() - t.Logf("output:\n%s", out) - - if err != nil { - t.Errorf("Was not expecting a crash") - } - return - } - - test := func(t *testing.T) { - t.Parallel() - defer func() { - recover() - }() - panic(nil) - } - t.Run("One", test) - t.Run("Two", test) -} - -func TestCmdBisect(t *testing.T) { - testenv.MustHaveGoRun(t) - out, err := exec.Command(testenv.GoToolPath(t), "run", "cmd/vendor/golang.org/x/tools/cmd/bisect", "GODEBUG=buggy=1#PATTERN", os.Args[0], "-test.run=^TestBisectTestCase$").CombinedOutput() - if err != nil { - t.Fatalf("exec bisect: %v\n%s", err, out) - } - - var want []string - src, err := os.ReadFile("godebug_test.go") - if err != nil { - t.Fatal(err) - } - for i, line := range strings.Split(string(src), "\n") { - if strings.Contains(line, "BISECT"+" "+"BUG") { - want = append(want, fmt.Sprintf("godebug_test.go:%d", i+1)) - } - } - slices.Sort(want) - - var have []string - for _, line := range strings.Split(string(out), "\n") { - if strings.Contains(line, "godebug_test.go:") { - have = append(have, line[strings.LastIndex(line, "godebug_test.go:"):]) - } - } - slices.Sort(have) - - if !slices.Equal(have, want) { - t.Errorf("bad bisect output:\nhave %v\nwant %v\ncomplete output:\n%s", have, want, string(out)) - } -} - -// This test does nothing by itself, but you can run -// -// bisect 'GODEBUG=buggy=1#PATTERN' go test -run='^TestBisectTestCase$' -// -// to see that the GODEBUG bisect support is working. -// TestCmdBisect above does exactly that. -func TestBisectTestCase(t *testing.T) { - s := New("#buggy") - for i := 0; i < 10; i++ { - a := s.Value() == "1" - b := s.Value() == "1" - c := s.Value() == "1" // BISECT BUG - d := s.Value() == "1" // BISECT BUG - e := s.Value() == "1" // BISECT BUG - - if a { - t.Log("ok") - } - if b { - t.Log("ok") - } - if c { - t.Error("bug") - } - if d && - e { - t.Error("bug") - } - } -} - -func TestImmutable(t *testing.T) { - defer func(godebug string) { - os.Setenv("GODEBUG", godebug) - }(os.Getenv("GODEBUG")) - - setting := New("fips140") - value := setting.Value() - - os.Setenv("GODEBUG", "fips140=off") - if setting.Value() != value { - t.Errorf("Value() changed after setting GODEBUG=fips140=off") - } - - os.Setenv("GODEBUG", "fips140=on") - if setting.Value() != value { - t.Errorf("Value() changed after setting GODEBUG=fips140=on") - } - - os.Setenv("GODEBUG", "fips140=") - if setting.Value() != value { - t.Errorf("Value() changed after setting GODEBUG=fips140=") - } - - os.Setenv("GODEBUG", "") - if setting.Value() != value { - t.Errorf("Value() changed after setting GODEBUG=") - } -} diff --git a/testing/internal/godebugs/godebugs_test.go b/testing/internal/godebugs/godebugs_test.go deleted file mode 100644 index 424b1966..00000000 --- a/testing/internal/godebugs/godebugs_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023 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 godebugs_test - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebugs" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "strings" - "testing" -) - -func TestAll(t *testing.T) { - testenv.MustHaveGoBuild(t) - - data, err := os.ReadFile("../../../doc/godebug.md") - if err != nil { - if os.IsNotExist(err) && (testenv.Builder() == "" || runtime.GOOS != "linux") { - t.Skip(err) - } - t.Fatal(err) - } - doc := string(data) - - incs := incNonDefaults(t) - - last := "" - for _, info := range godebugs.All { - if info.Name <= last { - t.Errorf("All not sorted: %s then %s", last, info.Name) - } - last = info.Name - - if info.Package == "" { - t.Errorf("Name=%s missing Package", info.Name) - } - if info.Changed != 0 && info.Old == "" { - t.Errorf("Name=%s has Changed, missing Old", info.Name) - } - if info.Old != "" && info.Changed == 0 { - t.Errorf("Name=%s has Old, missing Changed", info.Name) - } - if !strings.Contains(doc, "`"+info.Name+"`") && - !strings.Contains(doc, "`"+info.Name+"=") { - t.Errorf("Name=%s not documented in doc/godebug.md", info.Name) - } - if !info.Opaque && !incs[info.Name] { - t.Errorf("Name=%s missing IncNonDefault calls; see 'go doc internal/godebug'", info.Name) - } - } -} - -var incNonDefaultRE = regexp.MustCompile(`([\pL\p{Nd}_]+)\.IncNonDefault\(\)`) - -func incNonDefaults(t *testing.T) map[string]bool { - // Build list of all files importing internal/godebug. - // Tried a more sophisticated search in go list looking for - // imports containing "github.com/CodSpeedHQ/codspeed-go/testing/internal/godebug", but that turned - // up a bug in go list instead. #66218 - out, err := exec.Command("go", "list", "-f={{.Dir}}", "std", "cmd").CombinedOutput() - if err != nil { - t.Fatalf("go list: %v\n%s", err, out) - } - - seen := map[string]bool{} - for _, dir := range strings.Split(string(out), "\n") { - if dir == "" { - continue - } - files, err := os.ReadDir(dir) - if err != nil { - t.Fatal(err) - } - for _, file := range files { - name := file.Name() - if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { - continue - } - data, err := os.ReadFile(filepath.Join(dir, name)) - if err != nil { - t.Fatal(err) - } - for _, m := range incNonDefaultRE.FindAllSubmatch(data, -1) { - seen[string(m[1])] = true - } - } - } - return seen -} diff --git a/testing/internal/godebugs/table.go b/testing/internal/godebugs/table.go deleted file mode 100644 index 852305e8..00000000 --- a/testing/internal/godebugs/table.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2023 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 godebugs provides a table of known GODEBUG settings, -// for use by a variety of other packages, including internal/godebug, -// runtime, runtime/metrics, and cmd/go/internal/load. -package godebugs - -// An Info describes a single known GODEBUG setting. -type Info struct { - Name string // name of the setting ("panicnil") - Package string // package that uses the setting ("runtime") - Changed int // minor version when default changed, if any; 21 means Go 1.21 - Old string // value that restores behavior prior to Changed - Opaque bool // setting does not export information to runtime/metrics using [internal/godebug.Setting.IncNonDefault] - Immutable bool // setting cannot be changed after program start -} - -// All is the table of known settings, sorted by Name. -// -// Note: After adding entries to this table, run 'go generate runtime/metrics' -// to update the runtime/metrics doc comment. -// (Otherwise the runtime/metrics test will fail.) -// -// Note: After adding entries to this table, update the list in doc/godebug.md as well. -// (Otherwise the test in this package will fail.) -var All = []Info{ - {Name: "allowmultiplevcs", Package: "cmd/go"}, - {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"}, - {Name: "containermaxprocs", Package: "runtime", Changed: 25, Old: "0"}, - {Name: "dataindependenttiming", Package: "crypto/subtle", Opaque: true}, - {Name: "decoratemappings", Package: "runtime", Opaque: true, Changed: 25, Old: "0"}, - {Name: "embedfollowsymlinks", Package: "cmd/go"}, - {Name: "execerrdot", Package: "os/exec"}, - {Name: "fips140", Package: "crypto/fips140", Opaque: true, Immutable: true}, - {Name: "gocachehash", Package: "cmd/go"}, - {Name: "gocachetest", Package: "cmd/go"}, - {Name: "gocacheverify", Package: "cmd/go"}, - {Name: "gotestjsonbuildtext", Package: "cmd/go", Changed: 24, Old: "1"}, - {Name: "gotypesalias", Package: "go/types", Changed: 23, Old: "0"}, - {Name: "http2client", Package: "net/http"}, - {Name: "http2debug", Package: "net/http", Opaque: true}, - {Name: "http2server", Package: "net/http"}, - {Name: "httpcookiemaxnum", Package: "net/http", Changed: 24, Old: "0"}, - {Name: "httplaxcontentlength", Package: "net/http", Changed: 22, Old: "1"}, - {Name: "httpmuxgo121", Package: "net/http", Changed: 22, Old: "1"}, - {Name: "httpservecontentkeepheaders", Package: "net/http", Changed: 23, Old: "1"}, - {Name: "installgoroot", Package: "go/build"}, - {Name: "jstmpllitinterp", Package: "html/template", Opaque: true}, // bug #66217: remove Opaque - //{Name: "multipartfiles", Package: "mime/multipart"}, - {Name: "multipartmaxheaders", Package: "mime/multipart"}, - {Name: "multipartmaxparts", Package: "mime/multipart"}, - {Name: "multipathtcp", Package: "net", Changed: 24, Old: "0"}, - {Name: "netdns", Package: "net", Opaque: true}, - {Name: "netedns0", Package: "net", Changed: 19, Old: "0"}, - {Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"}, - {Name: "randautoseed", Package: "math/rand"}, - {Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"}, - {Name: "rsa1024min", Package: "crypto/rsa", Changed: 24, Old: "0"}, - {Name: "tarinsecurepath", Package: "archive/tar"}, - {Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"}, - {Name: "tls3des", Package: "crypto/tls", Changed: 23, Old: "1"}, - {Name: "tlsmaxrsasize", Package: "crypto/tls"}, - {Name: "tlsmlkem", Package: "crypto/tls", Changed: 24, Old: "0", Opaque: true}, - {Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"}, - {Name: "tlssha1", Package: "crypto/tls", Changed: 25, Old: "1"}, - {Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"}, - {Name: "updatemaxprocs", Package: "runtime", Changed: 25, Old: "0"}, - {Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"}, - {Name: "winsymlink", Package: "os", Changed: 23, Old: "0"}, - {Name: "x509keypairleaf", Package: "crypto/tls", Changed: 23, Old: "0"}, - {Name: "x509negativeserial", Package: "crypto/x509", Changed: 23, Old: "1"}, - {Name: "x509rsacrt", Package: "crypto/x509", Changed: 24, Old: "0"}, - {Name: "x509sha256skid", Package: "crypto/x509", Changed: 25, Old: "0"}, - {Name: "x509usefallbackroots", Package: "crypto/x509"}, - {Name: "x509usepolicies", Package: "crypto/x509", Changed: 24, Old: "0"}, - {Name: "zipinsecurepath", Package: "archive/zip"}, -} - -// Lookup returns the Info with the given name. -func Lookup(name string) *Info { - // binary search, avoiding import of sort. - lo := 0 - hi := len(All) - for lo < hi { - m := int(uint(lo+hi) >> 1) - mid := All[m].Name - if name == mid { - return &All[m] - } - if name < mid { - hi = m - } else { - lo = m + 1 - } - } - return nil -} diff --git a/testing/internal/platform/supported.go b/testing/internal/platform/supported.go deleted file mode 100644 index 7d25fd7e..00000000 --- a/testing/internal/platform/supported.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2018 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:generate go test . -run=^TestGenerated$ -fix - -package platform - -// An OSArch is a pair of GOOS and GOARCH values indicating a platform. -type OSArch struct { - GOOS, GOARCH string -} - -func (p OSArch) String() string { - return p.GOOS + "/" + p.GOARCH -} - -// RaceDetectorSupported reports whether goos/goarch supports the race -// detector. There is a copy of this function in cmd/dist/test.go. -// Race detector only supports 48-bit VMA on arm64. But it will always -// return true for arm64, because we don't have VMA size information during -// the compile time. -func RaceDetectorSupported(goos, goarch string) bool { - switch goos { - case "linux": - return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x" || goarch == "loong64" - case "darwin": - return goarch == "amd64" || goarch == "arm64" - case "freebsd", "netbsd", "windows": - return goarch == "amd64" - default: - return false - } -} - -// MSanSupported reports whether goos/goarch supports the memory -// sanitizer option. -func MSanSupported(goos, goarch string) bool { - switch goos { - case "linux": - return goarch == "amd64" || goarch == "arm64" || goarch == "loong64" - case "freebsd": - return goarch == "amd64" - default: - return false - } -} - -// ASanSupported reports whether goos/goarch supports the address -// sanitizer option. -func ASanSupported(goos, goarch string) bool { - switch goos { - case "linux": - return goarch == "arm64" || goarch == "amd64" || goarch == "loong64" || goarch == "riscv64" || goarch == "ppc64le" - default: - return false - } -} - -// FuzzSupported reports whether goos/goarch supports fuzzing -// ('go test -fuzz=.'). -func FuzzSupported(goos, goarch string) bool { - switch goos { - case "darwin", "freebsd", "linux", "openbsd", "windows": - return true - default: - return false - } -} - -// FuzzInstrumented reports whether fuzzing on goos/goarch uses coverage -// instrumentation. (FuzzInstrumented implies FuzzSupported.) -func FuzzInstrumented(goos, goarch string) bool { - switch goarch { - case "amd64", "arm64", "loong64": - // TODO(#14565): support more architectures. - return FuzzSupported(goos, goarch) - default: - return false - } -} - -// MustLinkExternal reports whether goos/goarch requires external linking -// with or without cgo dependencies. -func MustLinkExternal(goos, goarch string, withCgo bool) bool { - if withCgo { - switch goarch { - case "mips", "mipsle", "mips64", "mips64le": - // Internally linking cgo is incomplete on some architectures. - // https://go.dev/issue/14449 - return true - case "arm64": - if goos == "windows" { - // windows/arm64 internal linking is not implemented. - return true - } - case "ppc64": - // Big Endian PPC64 cgo internal linking is not implemented for aix or linux. - // https://go.dev/issue/8912 - if goos == "aix" || goos == "linux" { - return true - } - } - - switch goos { - case "android": - return true - case "dragonfly": - // It seems that on Dragonfly thread local storage is - // set up by the dynamic linker, so internal cgo linking - // doesn't work. Test case is "go test runtime/cgo". - return true - } - } - - switch goos { - case "android": - if goarch != "arm64" { - return true - } - case "ios": - if goarch == "arm64" { - return true - } - } - return false -} - -// BuildModeSupported reports whether goos/goarch supports the given build mode -// using the given compiler. -// There is a copy of this function in cmd/dist/test.go. -func BuildModeSupported(compiler, buildmode, goos, goarch string) bool { - if compiler == "gccgo" { - return true - } - - if _, ok := distInfo[OSArch{goos, goarch}]; !ok { - return false // platform unrecognized - } - - platform := goos + "/" + goarch - switch buildmode { - case "archive": - return true - - case "c-archive": - switch goos { - case "aix", "darwin", "ios", "windows": - return true - case "linux": - switch goarch { - case "386", "amd64", "arm", "armbe", "arm64", "arm64be", "loong64", "ppc64le", "riscv64", "s390x": - // linux/ppc64 not supported because it does - // not support external linking mode yet. - return true - default: - // Other targets do not support -shared, - // per ParseFlags in - // cmd/compile/internal/base/flag.go. - // For c-archive the Go tool passes -shared, - // so that the result is suitable for inclusion - // in a PIE or shared library. - return false - } - case "freebsd": - return goarch == "amd64" - } - return false - - case "c-shared": - switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/386", "linux/ppc64le", "linux/riscv64", "linux/s390x", - "android/amd64", "android/arm", "android/arm64", "android/386", - "freebsd/amd64", - "darwin/amd64", "darwin/arm64", - "windows/amd64", "windows/386", "windows/arm64", - "wasip1/wasm": - return true - } - return false - - case "default": - return true - - case "exe": - return true - - case "pie": - switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/ppc64le", "linux/riscv64", "linux/s390x", - "android/amd64", "android/arm", "android/arm64", "android/386", - "freebsd/amd64", - "darwin/amd64", "darwin/arm64", - "ios/amd64", "ios/arm64", - "aix/ppc64", - "openbsd/arm64", - "windows/386", "windows/amd64", "windows/arm", "windows/arm64": - return true - } - return false - - case "shared": - switch platform { - case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x": - return true - } - return false - - case "plugin": - switch platform { - case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/loong64", "linux/riscv64", "linux/s390x", "linux/ppc64le", - "android/amd64", "android/386", - "darwin/amd64", "darwin/arm64", - "freebsd/amd64": - return true - } - return false - - default: - return false - } -} - -func InternalLinkPIESupported(goos, goarch string) bool { - switch goos + "/" + goarch { - case "android/arm64", - "darwin/amd64", "darwin/arm64", - "linux/amd64", "linux/arm64", "linux/loong64", "linux/ppc64le", - "windows/386", "windows/amd64", "windows/arm", "windows/arm64": - return true - } - return false -} - -// DefaultPIE reports whether goos/goarch produces a PIE binary when using the -// "default" buildmode. On Windows this is affected by -race, -// so force the caller to pass that in to centralize that choice. -func DefaultPIE(goos, goarch string, isRace bool) bool { - switch goos { - case "android", "ios": - return true - case "windows": - if isRace { - // PIE is not supported with -race on windows; - // see https://go.dev/cl/416174. - return false - } - return true - case "darwin": - return true - } - return false -} - -// ExecutableHasDWARF reports whether the linked executable includes DWARF -// symbols on goos/goarch. -func ExecutableHasDWARF(goos, goarch string) bool { - switch goos { - case "plan9", "ios": - return false - } - return true -} - -// osArchInfo describes information about an OSArch extracted from cmd/dist and -// stored in the generated distInfo map. -type osArchInfo struct { - CgoSupported bool - FirstClass bool - Broken bool -} - -// CgoSupported reports whether goos/goarch supports cgo. -func CgoSupported(goos, goarch string) bool { - return distInfo[OSArch{goos, goarch}].CgoSupported -} - -// FirstClass reports whether goos/goarch is considered a “first class” port. -// (See https://go.dev/wiki/PortingPolicy#first-class-ports.) -func FirstClass(goos, goarch string) bool { - return distInfo[OSArch{goos, goarch}].FirstClass -} - -// Broken reports whether goos/goarch is considered a broken port. -// (See https://go.dev/wiki/PortingPolicy#broken-ports.) -func Broken(goos, goarch string) bool { - return distInfo[OSArch{goos, goarch}].Broken -} diff --git a/testing/internal/platform/zosarch.go b/testing/internal/platform/zosarch.go deleted file mode 100644 index ebde978a..00000000 --- a/testing/internal/platform/zosarch.go +++ /dev/null @@ -1,116 +0,0 @@ -// Code generated by go test internal/platform -fix. DO NOT EDIT. - -// To change the information in this file, edit the cgoEnabled and/or firstClass -// maps in cmd/dist/build.go, then run 'go generate internal/platform'. - -package platform - -// List is the list of all valid GOOS/GOARCH combinations, -// including known-broken ports. -var List = []OSArch{ - {"aix", "ppc64"}, - {"android", "386"}, - {"android", "amd64"}, - {"android", "arm"}, - {"android", "arm64"}, - {"darwin", "amd64"}, - {"darwin", "arm64"}, - {"dragonfly", "amd64"}, - {"freebsd", "386"}, - {"freebsd", "amd64"}, - {"freebsd", "arm"}, - {"freebsd", "arm64"}, - {"freebsd", "riscv64"}, - {"illumos", "amd64"}, - {"ios", "amd64"}, - {"ios", "arm64"}, - {"js", "wasm"}, - {"linux", "386"}, - {"linux", "amd64"}, - {"linux", "arm"}, - {"linux", "arm64"}, - {"linux", "loong64"}, - {"linux", "mips"}, - {"linux", "mips64"}, - {"linux", "mips64le"}, - {"linux", "mipsle"}, - {"linux", "ppc64"}, - {"linux", "ppc64le"}, - {"linux", "riscv64"}, - {"linux", "s390x"}, - {"linux", "sparc64"}, - {"netbsd", "386"}, - {"netbsd", "amd64"}, - {"netbsd", "arm"}, - {"netbsd", "arm64"}, - {"openbsd", "386"}, - {"openbsd", "amd64"}, - {"openbsd", "arm"}, - {"openbsd", "arm64"}, - {"openbsd", "mips64"}, - {"openbsd", "ppc64"}, - {"openbsd", "riscv64"}, - {"plan9", "386"}, - {"plan9", "amd64"}, - {"plan9", "arm"}, - {"solaris", "amd64"}, - {"wasip1", "wasm"}, - {"windows", "386"}, - {"windows", "amd64"}, - {"windows", "arm"}, - {"windows", "arm64"}, -} - -var distInfo = map[OSArch]osArchInfo{ - {"aix", "ppc64"}: {CgoSupported: true}, - {"android", "386"}: {CgoSupported: true}, - {"android", "amd64"}: {CgoSupported: true}, - {"android", "arm"}: {CgoSupported: true}, - {"android", "arm64"}: {CgoSupported: true}, - {"darwin", "amd64"}: {CgoSupported: true, FirstClass: true}, - {"darwin", "arm64"}: {CgoSupported: true, FirstClass: true}, - {"dragonfly", "amd64"}: {CgoSupported: true}, - {"freebsd", "386"}: {CgoSupported: true}, - {"freebsd", "amd64"}: {CgoSupported: true}, - {"freebsd", "arm"}: {CgoSupported: true}, - {"freebsd", "arm64"}: {CgoSupported: true}, - {"freebsd", "riscv64"}: {CgoSupported: true}, - {"illumos", "amd64"}: {CgoSupported: true}, - {"ios", "amd64"}: {CgoSupported: true}, - {"ios", "arm64"}: {CgoSupported: true}, - {"js", "wasm"}: {}, - {"linux", "386"}: {CgoSupported: true, FirstClass: true}, - {"linux", "amd64"}: {CgoSupported: true, FirstClass: true}, - {"linux", "arm"}: {CgoSupported: true, FirstClass: true}, - {"linux", "arm64"}: {CgoSupported: true, FirstClass: true}, - {"linux", "loong64"}: {CgoSupported: true}, - {"linux", "mips"}: {CgoSupported: true}, - {"linux", "mips64"}: {CgoSupported: true}, - {"linux", "mips64le"}: {CgoSupported: true}, - {"linux", "mipsle"}: {CgoSupported: true}, - {"linux", "ppc64"}: {}, - {"linux", "ppc64le"}: {CgoSupported: true}, - {"linux", "riscv64"}: {CgoSupported: true}, - {"linux", "s390x"}: {CgoSupported: true}, - {"linux", "sparc64"}: {CgoSupported: true, Broken: true}, - {"netbsd", "386"}: {CgoSupported: true}, - {"netbsd", "amd64"}: {CgoSupported: true}, - {"netbsd", "arm"}: {CgoSupported: true}, - {"netbsd", "arm64"}: {CgoSupported: true}, - {"openbsd", "386"}: {CgoSupported: true}, - {"openbsd", "amd64"}: {CgoSupported: true}, - {"openbsd", "arm"}: {CgoSupported: true}, - {"openbsd", "arm64"}: {CgoSupported: true}, - {"openbsd", "mips64"}: {CgoSupported: true, Broken: true}, - {"openbsd", "ppc64"}: {}, - {"openbsd", "riscv64"}: {CgoSupported: true}, - {"plan9", "386"}: {}, - {"plan9", "amd64"}: {}, - {"plan9", "arm"}: {}, - {"solaris", "amd64"}: {CgoSupported: true}, - {"wasip1", "wasm"}: {}, - {"windows", "386"}: {CgoSupported: true, FirstClass: true}, - {"windows", "amd64"}: {CgoSupported: true, FirstClass: true}, - {"windows", "arm"}: {Broken: true}, - {"windows", "arm64"}: {CgoSupported: true}, -} diff --git a/testing/internal/platform/zosarch_test.go b/testing/internal/platform/zosarch_test.go deleted file mode 100644 index d54b75ea..00000000 --- a/testing/internal/platform/zosarch_test.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2023 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 platform_test - -import ( - "bytes" - "encoding/json" - "flag" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/diff" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "testing" - "text/template" -) - -var flagFix = flag.Bool("fix", false, "if true, fix out-of-date generated files") - -// TestGenerated verifies that zosarch.go is up to date, -// or regenerates it if the -fix flag is set. -func TestGenerated(t *testing.T) { - testenv.MustHaveGoRun(t) - - // Here we use 'go run cmd/dist' instead of 'go tool dist' in case the - // installed cmd/dist is stale or missing. We don't want to miss a - // skew in the data due to a stale binary. - cmd := testenv.Command(t, "go", "run", "cmd/dist", "list", "-json", "-broken") - - // cmd/dist requires GOROOT to be set explicitly in the environment. - cmd.Env = append(cmd.Environ(), "GOROOT="+testenv.GOROOT(t)) - - out, err := cmd.Output() - if err != nil { - if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { - t.Logf("stderr:\n%s", ee.Stderr) - } - t.Fatalf("%v: %v", cmd, err) - } - - type listEntry struct { - GOOS, GOARCH string - CgoSupported bool - FirstClass bool - Broken bool - } - var entries []listEntry - if err := json.Unmarshal(out, &entries); err != nil { - t.Fatal(err) - } - - tmplOut := new(bytes.Buffer) - tmpl := template.Must(template.New("zosarch").Parse(zosarchTmpl)) - err = tmpl.Execute(tmplOut, entries) - if err != nil { - t.Fatal(err) - } - - cmd = testenv.Command(t, "gofmt") - cmd.Stdin = bytes.NewReader(tmplOut.Bytes()) - want, err := cmd.Output() - if err != nil { - t.Logf("stdin:\n%s", tmplOut.Bytes()) - if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { - t.Logf("stderr:\n%s", ee.Stderr) - } - t.Fatalf("%v: %v", cmd, err) - } - - got, err := os.ReadFile("zosarch.go") - if err == nil && bytes.Equal(got, want) { - return - } - - if !*flagFix { - if err != nil { - t.Log(err) - } else { - t.Logf("diff:\n%s", diff.Diff("zosarch.go", got, "want", want)) - } - t.Fatalf("zosarch.go is missing or out of date; to regenerate, run\ngo generate internal/platform") - } - - if err := os.WriteFile("zosarch.go", want, 0666); err != nil { - t.Fatal(err) - } -} - -const zosarchTmpl = `// Code generated by go test internal/platform -fix. DO NOT EDIT. - -// To change the information in this file, edit the cgoEnabled and/or firstClass -// maps in cmd/dist/build.go, then run 'go generate internal/platform'. - -package platform - -// List is the list of all valid GOOS/GOARCH combinations, -// including known-broken ports. -var List = []OSArch{ -{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} }, -{{end}} -} - -var distInfo = map[OSArch]osArchInfo { -{{range .}} { {{ printf "%q" .GOOS }}, {{ printf "%q" .GOARCH }} }: -{ {{if .CgoSupported}}CgoSupported: true, {{end}}{{if .FirstClass}}FirstClass: true, {{end}}{{if .Broken}} Broken: true, {{end}} }, -{{end}} -} -` diff --git a/testing/internal/race/doc.go b/testing/internal/race/doc.go deleted file mode 100644 index 8fa44ce6..00000000 --- a/testing/internal/race/doc.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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 race contains helper functions for manually instrumenting code for the race detector. - -The runtime package intentionally exports these functions only in the race build; -this package exports them unconditionally but without the "race" build tag they are no-ops. -*/ -package race diff --git a/testing/internal/race/norace.go b/testing/internal/race/norace.go deleted file mode 100644 index 49d68a4d..00000000 --- a/testing/internal/race/norace.go +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -//go:build !race - -package race - -import ( - // "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" - "unsafe" -) - -const Enabled = false - -func Acquire(addr unsafe.Pointer) { -} - -func Release(addr unsafe.Pointer) { -} - -func ReleaseMerge(addr unsafe.Pointer) { -} - -func Disable() { -} - -func Enable() { -} - -func Read(addr unsafe.Pointer) { -} - -func ReadPC(addr unsafe.Pointer, callerpc, pc uintptr) { -} - -// func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { -// } - -func Write(addr unsafe.Pointer) { -} - -func WritePC(addr unsafe.Pointer, callerpc, pc uintptr) { -} - -// func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { -// } - -func ReadRange(addr unsafe.Pointer, len int) { -} - -func WriteRange(addr unsafe.Pointer, len int) { -} - -func Errors() int { return 0 } diff --git a/testing/internal/race/race.go b/testing/internal/race/race.go deleted file mode 100644 index ef54ea51..00000000 --- a/testing/internal/race/race.go +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -//go:build race - -package race - -import ( - "unsafe" -) - -const Enabled = true - -// Functions below pushed from runtime. - -//go:linkname Acquire -func Acquire(addr unsafe.Pointer) - -//go:linkname Release -func Release(addr unsafe.Pointer) - -//go:linkname ReleaseMerge -func ReleaseMerge(addr unsafe.Pointer) - -//go:linkname Disable -func Disable() - -//go:linkname Enable -func Enable() - -//go:linkname Read -func Read(addr unsafe.Pointer) - -//go:linkname ReadPC -func ReadPC(addr unsafe.Pointer, callerpc, pc uintptr) - -// //go:linkname ReadObjectPC -// func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) - -//go:linkname Write -func Write(addr unsafe.Pointer) - -//go:linkname WritePC -func WritePC(addr unsafe.Pointer, callerpc, pc uintptr) - -// //go:linkname WriteObjectPC -// func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) - -//go:linkname ReadRange -func ReadRange(addr unsafe.Pointer, len int) - -//go:linkname WriteRange -func WriteRange(addr unsafe.Pointer, len int) - -//go:linkname Errors -func Errors() int diff --git a/testing/internal/synctest/synctest.go b/testing/internal/synctest/synctest.go deleted file mode 100644 index c1c55756..00000000 --- a/testing/internal/synctest/synctest.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2024 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 synctest provides support for testing concurrent code. -// -// See the testing/synctest package for function documentation. -package synctest - -import ( - // "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" - "unsafe" -) - -//go:linkname Run -func Run(f func()) - -//go:linkname Wait -func Wait() - -// IsInBubble reports whether the current goroutine is in a bubble. -// -//go:linkname IsInBubble -func IsInBubble() bool - -// Association is the state of a pointer's bubble association. -type Association int - -const ( - Unbubbled = Association(iota) // not associated with any bubble - CurrentBubble // associated with the current bubble - OtherBubble // associated with a different bubble -) - -// Manual import of `Escape` to avoid the `internal/abi` dependency which contains assembly functions, which would -// lead to linker errors due to duplicate symbols. -var alwaysFalse bool -var escapeSink any - -// Escape forces any pointers in x to escape to the heap. -func Escape[T any](x T) T { - if alwaysFalse { - escapeSink = x - } - return x -} - -// Associate attempts to associate p with the current bubble. -// It returns the new association status of p. -func Associate[T any](p *T) Association { - // Ensure p escapes to permit us to attach a special to it. - escapedP := Escape(p) - return Association(associate(unsafe.Pointer(escapedP))) -} - -//go:linkname associate -func associate(p unsafe.Pointer) int - -// Disassociate disassociates p from any bubble. -func Disassociate[T any](p *T) { - disassociate(unsafe.Pointer(p)) -} - -//go:linkname disassociate -func disassociate(b unsafe.Pointer) - -// IsAssociated reports whether p is associated with the current bubble. -func IsAssociated[T any](p *T) bool { - return isAssociated(unsafe.Pointer(p)) -} - -//go:linkname isAssociated -func isAssociated(p unsafe.Pointer) bool - -//go:linkname acquire -func acquire() any - -//go:linkname release -func release(any) - -//go:linkname inBubble -func inBubble(any, func()) - -// A Bubble is a synctest bubble. -// -// Not a public API. Used by syscall/js to propagate bubble membership through syscalls. -type Bubble struct { - b any -} - -// Acquire returns a reference to the current goroutine's bubble. -// The bubble will not become idle until Release is called. -func Acquire() *Bubble { - if b := acquire(); b != nil { - return &Bubble{b} - } - return nil -} - -// Release releases the reference to the bubble, -// allowing it to become idle again. -func (b *Bubble) Release() { - if b == nil { - return - } - release(b.b) - b.b = nil -} - -// Run executes f in the bubble. -// The current goroutine must not be part of a bubble. -func (b *Bubble) Run(f func()) { - if b == nil { - f() - } else { - inBubble(b.b, f) - } -} diff --git a/testing/internal/synctest/synctest_test.go b/testing/internal/synctest/synctest_test.go deleted file mode 100644 index 3541a659..00000000 --- a/testing/internal/synctest/synctest_test.go +++ /dev/null @@ -1,930 +0,0 @@ -// Copyright 2024 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 synctest_test - -import ( - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/synctest" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "iter" - "os" - "reflect" - "runtime" - "slices" - "strconv" - "strings" - "sync" - "sync/atomic" - "testing" - "time" - "weak" -) - -func TestNow(t *testing.T) { - start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).In(time.Local) - synctest.Run(func() { - // Time starts at 2000-1-1 00:00:00. - if got, want := time.Now(), start; !got.Equal(want) { - t.Errorf("at start: time.Now = %v, want %v", got, want) - } - go func() { - // New goroutines see the same fake clock. - if got, want := time.Now(), start; !got.Equal(want) { - t.Errorf("time.Now = %v, want %v", got, want) - } - }() - // Time advances after a sleep. - time.Sleep(1 * time.Second) - if got, want := time.Now(), start.Add(1*time.Second); !got.Equal(want) { - t.Errorf("after sleep: time.Now = %v, want %v", got, want) - } - }) -} - -// TestMonotonicClock exercises comparing times from within a bubble -// with ones from outside the bubble. -func TestMonotonicClock(t *testing.T) { - start := time.Now() - synctest.Run(func() { - time.Sleep(time.Until(start.Round(0))) - if got, want := time.Now().In(time.UTC), start.In(time.UTC); !got.Equal(want) { - t.Fatalf("time.Now() = %v, want %v", got, want) - } - - wait := 1 * time.Second - time.Sleep(wait) - if got := time.Since(start); got != wait { - t.Fatalf("time.Since(start) = %v, want %v", got, wait) - } - if got := time.Now().Sub(start); got != wait { - t.Fatalf("time.Now().Sub(start) = %v, want %v", got, wait) - } - }) -} - -func TestRunEmpty(t *testing.T) { - synctest.Run(func() { - }) -} - -func TestSimpleWait(t *testing.T) { - synctest.Run(func() { - synctest.Wait() - }) -} - -func TestGoroutineWait(t *testing.T) { - synctest.Run(func() { - go func() {}() - synctest.Wait() - }) -} - -// TestWait starts a collection of goroutines. -// It checks that synctest.Wait waits for all goroutines to exit before returning. -func TestWait(t *testing.T) { - synctest.Run(func() { - done := false - ch := make(chan int) - var f func() - f = func() { - count := <-ch - if count == 0 { - done = true - } else { - go f() - ch <- count - 1 - } - } - go f() - ch <- 100 - synctest.Wait() - if !done { - t.Fatalf("done = false, want true") - } - }) -} - -func TestMallocs(t *testing.T) { - for i := 0; i < 100; i++ { - synctest.Run(func() { - done := false - ch := make(chan []byte) - var f func() - f = func() { - b := <-ch - if len(b) == 0 { - done = true - } else { - go f() - ch <- make([]byte, len(b)-1) - } - } - go f() - ch <- make([]byte, 100) - synctest.Wait() - if !done { - t.Fatalf("done = false, want true") - } - }) - } -} - -func TestTimerReadBeforeDeadline(t *testing.T) { - synctest.Run(func() { - start := time.Now() - tm := time.NewTimer(5 * time.Second) - <-tm.C - if got, want := time.Since(start), 5*time.Second; got != want { - t.Errorf("after sleep: time.Since(start) = %v, want %v", got, want) - } - }) -} - -func TestTimerReadAfterDeadline(t *testing.T) { - synctest.Run(func() { - delay := 1 * time.Second - want := time.Now().Add(delay) - tm := time.NewTimer(delay) - time.Sleep(2 * delay) - got := <-tm.C - if got != want { - t.Errorf("<-tm.C = %v, want %v", got, want) - } - }) -} - -func TestTimerReset(t *testing.T) { - synctest.Run(func() { - start := time.Now() - tm := time.NewTimer(1 * time.Second) - if got, want := <-tm.C, start.Add(1*time.Second); got != want { - t.Errorf("first sleep: <-tm.C = %v, want %v", got, want) - } - - tm.Reset(2 * time.Second) - if got, want := <-tm.C, start.Add((1+2)*time.Second); got != want { - t.Errorf("second sleep: <-tm.C = %v, want %v", got, want) - } - - tm.Reset(3 * time.Second) - time.Sleep(1 * time.Second) - tm.Reset(3 * time.Second) - if got, want := <-tm.C, start.Add((1+2+4)*time.Second); got != want { - t.Errorf("third sleep: <-tm.C = %v, want %v", got, want) - } - }) -} - -func TestTimeAfter(t *testing.T) { - synctest.Run(func() { - i := 0 - time.AfterFunc(1*time.Second, func() { - // Ensure synctest group membership propagates through the AfterFunc. - i++ // 1 - go func() { - time.Sleep(1 * time.Second) - i++ // 2 - }() - }) - time.Sleep(3 * time.Second) - synctest.Wait() - if got, want := i, 2; got != want { - t.Errorf("after sleep and wait: i = %v, want %v", got, want) - } - }) -} - -func TestTimerAfterBubbleExit(t *testing.T) { - run := false - synctest.Run(func() { - time.AfterFunc(1*time.Second, func() { - run = true - }) - }) - if run { - t.Errorf("timer ran before bubble exit") - } -} - -func TestTimerFromOutsideBubble(t *testing.T) { - tm := time.NewTimer(10 * time.Millisecond) - synctest.Run(func() { - <-tm.C - }) - if tm.Stop() { - t.Errorf("synctest.Run unexpectedly returned before timer fired") - } -} - -// TestTimerNondeterminism verifies that timers firing at the same instant -// don't always fire in exactly the same order. -func TestTimerNondeterminism(t *testing.T) { - synctest.Run(func() { - const iterations = 1000 - var seen1, seen2 bool - for range iterations { - tm1 := time.NewTimer(1) - tm2 := time.NewTimer(1) - select { - case <-tm1.C: - seen1 = true - case <-tm2.C: - seen2 = true - } - if seen1 && seen2 { - return - } - synctest.Wait() - } - t.Errorf("after %v iterations, seen timer1:%v, timer2:%v; want both", iterations, seen1, seen2) - }) -} - -// TestSleepNondeterminism verifies that goroutines sleeping to the same instant -// don't always schedule in exactly the same order. -func TestSleepNondeterminism(t *testing.T) { - synctest.Run(func() { - const iterations = 1000 - var seen1, seen2 bool - for range iterations { - var first atomic.Int32 - go func() { - time.Sleep(1) - first.CompareAndSwap(0, 1) - }() - go func() { - time.Sleep(1) - first.CompareAndSwap(0, 2) - }() - time.Sleep(1) - synctest.Wait() - switch v := first.Load(); v { - case 1: - seen1 = true - case 2: - seen2 = true - default: - t.Fatalf("first = %v, want 1 or 2", v) - } - if seen1 && seen2 { - return - } - synctest.Wait() - } - t.Errorf("after %v iterations, seen goroutine 1:%v, 2:%v; want both", iterations, seen1, seen2) - }) -} - -// TestTimerRunsImmediately verifies that a 0-duration timer sends on its channel -// without waiting for the bubble to block. -func TestTimerRunsImmediately(t *testing.T) { - synctest.Run(func() { - start := time.Now() - tm := time.NewTimer(0) - select { - case got := <-tm.C: - if !got.Equal(start) { - t.Errorf("<-tm.C = %v, want %v", got, start) - } - default: - t.Errorf("0-duration timer channel is not readable; want it to be") - } - }) -} - -// TestTimerRunsLater verifies that reading from a timer's channel receives the -// timer fired, even when that time is in reading from a timer's channel receives the -// time the timer fired, even when that time is in the past. -func TestTimerRanInPast(t *testing.T) { - synctest.Run(func() { - delay := 1 * time.Second - want := time.Now().Add(delay) - tm := time.NewTimer(delay) - time.Sleep(2 * delay) - select { - case got := <-tm.C: - if !got.Equal(want) { - t.Errorf("<-tm.C = %v, want %v", got, want) - } - default: - t.Errorf("0-duration timer channel is not readable; want it to be") - } - }) -} - -// TestAfterFuncRunsImmediately verifies that a 0-duration AfterFunc is scheduled -// without waiting for the bubble to block. -func TestAfterFuncRunsImmediately(t *testing.T) { - synctest.Run(func() { - var b atomic.Bool - time.AfterFunc(0, func() { - b.Store(true) - }) - for !b.Load() { - runtime.Gosched() - } - }) -} - -func TestChannelFromOutsideBubble(t *testing.T) { - choutside := make(chan struct{}) - for _, test := range []struct { - desc string - outside func(ch chan int) - inside func(ch chan int) - }{{ - desc: "read closed", - outside: func(ch chan int) { close(ch) }, - inside: func(ch chan int) { <-ch }, - }, { - desc: "read value", - outside: func(ch chan int) { ch <- 0 }, - inside: func(ch chan int) { <-ch }, - }, { - desc: "write value", - outside: func(ch chan int) { <-ch }, - inside: func(ch chan int) { ch <- 0 }, - }, { - desc: "select outside only", - outside: func(ch chan int) { close(ch) }, - inside: func(ch chan int) { - select { - case <-ch: - case <-choutside: - } - }, - }, { - desc: "select mixed", - outside: func(ch chan int) { close(ch) }, - inside: func(ch chan int) { - ch2 := make(chan struct{}) - select { - case <-ch: - case <-ch2: - } - }, - }} { - t.Run(test.desc, func(t *testing.T) { - ch := make(chan int) - time.AfterFunc(1*time.Millisecond, func() { - test.outside(ch) - }) - synctest.Run(func() { - test.inside(ch) - }) - }) - } -} - -func TestChannelMovedOutOfBubble(t *testing.T) { - for _, test := range []struct { - desc string - f func(chan struct{}) - wantFatal string - }{{ - desc: "receive", - f: func(ch chan struct{}) { - <-ch - }, - wantFatal: "receive on synctest channel from outside bubble", - }, { - desc: "send", - f: func(ch chan struct{}) { - ch <- struct{}{} - }, - wantFatal: "send on synctest channel from outside bubble", - }, { - desc: "close", - f: func(ch chan struct{}) { - close(ch) - }, - wantFatal: "close of synctest channel from outside bubble", - }} { - t.Run(test.desc, func(t *testing.T) { - // Bubbled channel accessed from outside any bubble. - t.Run("outside_bubble", func(t *testing.T) { - wantFatal(t, test.wantFatal, func() { - donec := make(chan struct{}) - ch := make(chan chan struct{}) - go func() { - defer close(donec) - test.f(<-ch) - }() - synctest.Run(func() { - ch <- make(chan struct{}) - }) - <-donec - }) - }) - // Bubbled channel accessed from a different bubble. - t.Run("different_bubble", func(t *testing.T) { - wantFatal(t, test.wantFatal, func() { - donec := make(chan struct{}) - ch := make(chan chan struct{}) - go func() { - defer close(donec) - c := <-ch - synctest.Run(func() { - test.f(c) - }) - }() - synctest.Run(func() { - ch <- make(chan struct{}) - }) - <-donec - }) - }) - }) - } -} - -func TestTimerFromInsideBubble(t *testing.T) { - for _, test := range []struct { - desc string - f func(tm *time.Timer) - wantFatal string - }{{ - desc: "read channel", - f: func(tm *time.Timer) { - <-tm.C - }, - wantFatal: "receive on synctest channel from outside bubble", - }, { - desc: "Reset", - f: func(tm *time.Timer) { - tm.Reset(1 * time.Second) - }, - wantFatal: "reset of synctest timer from outside bubble", - }, { - desc: "Stop", - f: func(tm *time.Timer) { - tm.Stop() - }, - wantFatal: "stop of synctest timer from outside bubble", - }} { - t.Run(test.desc, func(t *testing.T) { - wantFatal(t, test.wantFatal, func() { - donec := make(chan struct{}) - ch := make(chan *time.Timer) - go func() { - defer close(donec) - test.f(<-ch) - }() - synctest.Run(func() { - tm := time.NewTimer(1 * time.Second) - ch <- tm - }) - <-donec - }) - }) - } -} - -func TestDeadlockRoot(t *testing.T) { - defer wantPanic(t, "deadlock: all goroutines in bubble are blocked") - synctest.Run(func() { - select {} - }) -} - -func TestDeadlockChild(t *testing.T) { - defer wantPanic(t, "deadlock: main bubble goroutine has exited but blocked goroutines remain") - synctest.Run(func() { - go func() { - select {} - }() - }) -} - -func TestDeadlockTicker(t *testing.T) { - defer wantPanic(t, "deadlock: main bubble goroutine has exited but blocked goroutines remain") - synctest.Run(func() { - go func() { - for range time.Tick(1 * time.Second) { - t.Errorf("ticker unexpectedly ran") - return - } - }() - }) -} - -func TestCond(t *testing.T) { - synctest.Run(func() { - var mu sync.Mutex - cond := sync.NewCond(&mu) - start := time.Now() - const waitTime = 1 * time.Millisecond - - go func() { - // Signal the cond. - time.Sleep(waitTime) - mu.Lock() - cond.Signal() - mu.Unlock() - - // Broadcast to the cond. - time.Sleep(waitTime) - mu.Lock() - cond.Broadcast() - mu.Unlock() - }() - - // Wait for cond.Signal. - mu.Lock() - cond.Wait() - mu.Unlock() - if got, want := time.Since(start), waitTime; got != want { - t.Errorf("after cond.Signal: time elapsed = %v, want %v", got, want) - } - - // Wait for cond.Broadcast in two goroutines. - waiterDone := false - go func() { - mu.Lock() - cond.Wait() - mu.Unlock() - waiterDone = true - }() - mu.Lock() - cond.Wait() - mu.Unlock() - synctest.Wait() - if !waiterDone { - t.Errorf("after cond.Broadcast: waiter not done") - } - if got, want := time.Since(start), 2*waitTime; got != want { - t.Errorf("after cond.Broadcast: time elapsed = %v, want %v", got, want) - } - }) -} - -func TestIteratorPush(t *testing.T) { - synctest.Run(func() { - seq := func(yield func(time.Time) bool) { - for yield(time.Now()) { - time.Sleep(1 * time.Second) - } - } - var got []time.Time - go func() { - for now := range seq { - got = append(got, now) - if len(got) >= 3 { - break - } - } - }() - want := []time.Time{ - time.Now(), - time.Now().Add(1 * time.Second), - time.Now().Add(2 * time.Second), - } - time.Sleep(5 * time.Second) - synctest.Wait() - if !slices.Equal(got, want) { - t.Errorf("got: %v; want: %v", got, want) - } - }) -} - -func TestIteratorPull(t *testing.T) { - synctest.Run(func() { - seq := func(yield func(time.Time) bool) { - for yield(time.Now()) { - time.Sleep(1 * time.Second) - } - } - var got []time.Time - go func() { - next, stop := iter.Pull(seq) - defer stop() - for len(got) < 3 { - now, _ := next() - got = append(got, now) - } - }() - want := []time.Time{ - time.Now(), - time.Now().Add(1 * time.Second), - time.Now().Add(2 * time.Second), - } - time.Sleep(5 * time.Second) - synctest.Wait() - if !slices.Equal(got, want) { - t.Errorf("got: %v; want: %v", got, want) - } - }) -} - -func TestReflectFuncOf(t *testing.T) { - mkfunc := func(name string, i int) { - reflect.FuncOf([]reflect.Type{ - reflect.StructOf([]reflect.StructField{{ - Name: name + strconv.Itoa(i), - Type: reflect.TypeOf(0), - }}), - }, nil, false) - } - go func() { - for i := 0; i < 100000; i++ { - mkfunc("A", i) - } - }() - synctest.Run(func() { - for i := 0; i < 100000; i++ { - mkfunc("A", i) - } - }) -} - -func TestWaitGroupInBubble(t *testing.T) { - synctest.Run(func() { - var wg sync.WaitGroup - wg.Add(1) - const delay = 1 * time.Second - go func() { - time.Sleep(delay) - wg.Done() - }() - start := time.Now() - wg.Wait() - if got := time.Since(start); got != delay { - t.Fatalf("WaitGroup.Wait() took %v, want %v", got, delay) - } - }) -} - -// https://go.dev/issue/74386 -func TestWaitGroupRacingAdds(t *testing.T) { - synctest.Run(func() { - var wg sync.WaitGroup - for range 100 { - wg.Go(func() {}) - } - wg.Wait() - }) -} - -func TestWaitGroupOutOfBubble(t *testing.T) { - var wg sync.WaitGroup - wg.Add(1) - donec := make(chan struct{}) - go synctest.Run(func() { - // Since wg.Add was called outside the bubble, Wait is not durably blocking - // and this waits until wg.Done is called below. - wg.Wait() - close(donec) - }) - select { - case <-donec: - t.Fatalf("synctest.Run finished before WaitGroup.Done called") - case <-time.After(1 * time.Millisecond): - } - wg.Done() - <-donec -} - -func TestWaitGroupMovedIntoBubble(t *testing.T) { - wantFatal(t, "fatal error: sync: WaitGroup.Add called from inside and outside synctest bubble", func() { - var wg sync.WaitGroup - wg.Add(1) - synctest.Run(func() { - wg.Add(1) - }) - }) -} - -func TestWaitGroupMovedOutOfBubble(t *testing.T) { - wantFatal(t, "fatal error: sync: WaitGroup.Add called from inside and outside synctest bubble", func() { - var wg sync.WaitGroup - synctest.Run(func() { - wg.Add(1) - }) - wg.Add(1) - }) -} - -func TestWaitGroupMovedBetweenBubblesWithNonZeroCount(t *testing.T) { - wantFatal(t, "fatal error: sync: WaitGroup.Add called from multiple synctest bubbles", func() { - var wg sync.WaitGroup - synctest.Run(func() { - wg.Add(1) - }) - synctest.Run(func() { - wg.Add(1) - }) - }) -} - -func TestWaitGroupDisassociateInWait(t *testing.T) { - var wg sync.WaitGroup - synctest.Run(func() { - wg.Add(1) - wg.Done() - // Count and waiters are 0, so Wait disassociates the WaitGroup. - wg.Wait() - }) - synctest.Run(func() { - // Reusing the WaitGroup is safe, because it is no longer bubbled. - wg.Add(1) - wg.Done() - }) -} - -func TestWaitGroupDisassociateInAdd(t *testing.T) { - var wg sync.WaitGroup - synctest.Run(func() { - wg.Add(1) - go wg.Wait() - synctest.Wait() // wait for Wait to block - // Count is 0 and waiters != 0, so Done wakes the waiters and - // disassociates the WaitGroup. - wg.Done() - }) - synctest.Run(func() { - // Reusing the WaitGroup is safe, because it is no longer bubbled. - wg.Add(1) - wg.Done() - }) -} - -var testWaitGroupLinkerAllocatedWG sync.WaitGroup - -func TestWaitGroupLinkerAllocated(t *testing.T) { - synctest.Run(func() { - // This WaitGroup is probably linker-allocated and has no span, - // so we won't be able to add a special to it associating it with - // this bubble. - // - // Operations on it may not be durably blocking, - // but they shouldn't fail. - testWaitGroupLinkerAllocatedWG.Go(func() {}) - testWaitGroupLinkerAllocatedWG.Wait() - }) -} - -var testWaitGroupHeapAllocatedWG = new(sync.WaitGroup) - -func TestWaitGroupHeapAllocated(t *testing.T) { - synctest.Run(func() { - // This package-scoped WaitGroup var should have been heap-allocated, - // so we can associate it with a bubble. - testWaitGroupHeapAllocatedWG.Add(1) - go testWaitGroupHeapAllocatedWG.Wait() - synctest.Wait() - testWaitGroupHeapAllocatedWG.Done() - }) -} - -// Issue #75134: Many racing bubble associations. -func TestWaitGroupManyBubbles(t *testing.T) { - var wg sync.WaitGroup - for range 100 { - wg.Go(func() { - synctest.Run(func() { - cancelc := make(chan struct{}) - var wg2 sync.WaitGroup - for range 100 { - wg2.Go(func() { - <-cancelc - }) - } - synctest.Wait() - close(cancelc) - wg2.Wait() - }) - }) - } - wg.Wait() -} - -func TestHappensBefore(t *testing.T) { - // Use two parallel goroutines accessing different vars to ensure that - // we correctly account for multiple goroutines in the bubble. - var v1 int - var v2 int - synctest.Run(func() { - v1++ // 1 - v2++ // 1 - - // Wait returns after these goroutines exit. - go func() { - v1++ // 2 - }() - go func() { - v2++ // 2 - }() - synctest.Wait() - - v1++ // 3 - v2++ // 3 - - // Wait returns after these goroutines block. - ch1 := make(chan struct{}) - go func() { - v1++ // 4 - <-ch1 - }() - go func() { - v2++ // 4 - <-ch1 - }() - synctest.Wait() - - v1++ // 5 - v2++ // 5 - close(ch1) - - // Wait returns after these timers run. - time.AfterFunc(0, func() { - v1++ // 6 - }) - time.AfterFunc(0, func() { - v2++ // 6 - }) - synctest.Wait() - - v1++ // 7 - v2++ // 7 - - // Wait returns after these timer goroutines block. - ch2 := make(chan struct{}) - time.AfterFunc(0, func() { - v1++ // 8 - <-ch2 - }) - time.AfterFunc(0, func() { - v2++ // 8 - <-ch2 - }) - synctest.Wait() - - v1++ // 9 - v2++ // 9 - close(ch2) - }) - // This Run happens after the previous Run returns. - synctest.Run(func() { - go func() { - go func() { - v1++ // 10 - }() - }() - go func() { - go func() { - v2++ // 10 - }() - }() - }) - // These tests happen after Run returns. - if got, want := v1, 10; got != want { - t.Errorf("v1 = %v, want %v", got, want) - } - if got, want := v2, 10; got != want { - t.Errorf("v2 = %v, want %v", got, want) - } -} - -// https://go.dev/issue/73817 -func TestWeak(t *testing.T) { - synctest.Run(func() { - for range 5 { - runtime.GC() - b := make([]byte, 1024) - weak.Make(&b) - } - }) -} - -func wantPanic(t *testing.T, want string) { - if e := recover(); e != nil { - if got := fmt.Sprint(e); got != want { - t.Errorf("got panic message %q, want %q", got, want) - } - } else { - t.Errorf("got no panic, want one") - } -} - -func wantFatal(t *testing.T, want string, f func()) { - t.Helper() - - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - f() - return - } - - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$") - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") - out, err := cmd.CombinedOutput() - if err == nil { - t.Errorf("expected test function to panic, but test returned successfully") - } - if !strings.Contains(string(out), want) { - t.Errorf("wanted test output contaiing %q; got %q", want, string(out)) - } -} diff --git a/testing/internal/syscall/windows/at_windows.go b/testing/internal/syscall/windows/at_windows.go deleted file mode 100644 index 41cdaf0d..00000000 --- a/testing/internal/syscall/windows/at_windows.go +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright 2024 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 windows - -import ( - "runtime" - "structs" - "syscall" - "unsafe" -) - -// Openat flags not supported by syscall.Open. -// -// These are invented values. -// -// When adding a new flag here, add an unexported version to -// the set of invented O_ values in syscall/types_windows.go -// to avoid overlap. -const ( - O_DIRECTORY = 0x100000 // target must be a directory - O_NOFOLLOW_ANY = 0x20000000 // disallow symlinks anywhere in the path - O_OPEN_REPARSE = 0x40000000 // FILE_OPEN_REPARSE_POINT, used by Lstat - O_WRITE_ATTRS = 0x80000000 // FILE_WRITE_ATTRIBUTES, used by Chmod -) - -func Openat(dirfd syscall.Handle, name string, flag uint64, perm uint32) (_ syscall.Handle, e1 error) { - if len(name) == 0 { - return syscall.InvalidHandle, syscall.ERROR_FILE_NOT_FOUND - } - - var access, options uint32 - switch flag & (syscall.O_RDONLY | syscall.O_WRONLY | syscall.O_RDWR) { - case syscall.O_RDONLY: - // FILE_GENERIC_READ includes FILE_LIST_DIRECTORY. - access = FILE_GENERIC_READ - case syscall.O_WRONLY: - access = FILE_GENERIC_WRITE - options |= FILE_NON_DIRECTORY_FILE - case syscall.O_RDWR: - access = FILE_GENERIC_READ | FILE_GENERIC_WRITE - options |= FILE_NON_DIRECTORY_FILE - default: - // Stat opens files without requesting read or write permissions, - // but we still need to request SYNCHRONIZE. - access = SYNCHRONIZE - } - if flag&syscall.O_CREAT != 0 { - access |= FILE_GENERIC_WRITE - } - if flag&syscall.O_APPEND != 0 { - access |= FILE_APPEND_DATA - // Remove FILE_WRITE_DATA access unless O_TRUNC is set, - // in which case we need it to truncate the file. - if flag&syscall.O_TRUNC == 0 { - access &^= FILE_WRITE_DATA - } - } - if flag&O_DIRECTORY != 0 { - options |= FILE_DIRECTORY_FILE - access |= FILE_LIST_DIRECTORY - } - if flag&syscall.O_SYNC != 0 { - options |= FILE_WRITE_THROUGH - } - if flag&O_WRITE_ATTRS != 0 { - access |= FILE_WRITE_ATTRIBUTES - } - // Allow File.Stat. - access |= STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA - - objAttrs := &OBJECT_ATTRIBUTES{} - if flag&O_NOFOLLOW_ANY != 0 { - objAttrs.Attributes |= OBJ_DONT_REPARSE - } - if flag&syscall.O_CLOEXEC == 0 { - objAttrs.Attributes |= OBJ_INHERIT - } - if err := objAttrs.init(dirfd, name); err != nil { - return syscall.InvalidHandle, err - } - - if flag&O_OPEN_REPARSE != 0 { - options |= FILE_OPEN_REPARSE_POINT - } - - // We don't use FILE_OVERWRITE/FILE_OVERWRITE_IF, because when opening - // a file with FILE_ATTRIBUTE_READONLY these will replace an existing - // file with a new, read-only one. - // - // Instead, we ftruncate the file after opening when O_TRUNC is set. - var disposition uint32 - switch { - case flag&(syscall.O_CREAT|syscall.O_EXCL) == (syscall.O_CREAT | syscall.O_EXCL): - disposition = FILE_CREATE - options |= FILE_OPEN_REPARSE_POINT // don't follow symlinks - case flag&syscall.O_CREAT == syscall.O_CREAT: - disposition = FILE_OPEN_IF - default: - disposition = FILE_OPEN - } - - fileAttrs := uint32(FILE_ATTRIBUTE_NORMAL) - if perm&syscall.S_IWRITE == 0 { - fileAttrs = FILE_ATTRIBUTE_READONLY - } - - var h syscall.Handle - err := NtCreateFile( - &h, - SYNCHRONIZE|access, - objAttrs, - &IO_STATUS_BLOCK{}, - nil, - fileAttrs, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - disposition, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_OPEN_FOR_BACKUP_INTENT|options, - nil, - 0, - ) - if err != nil { - return h, ntCreateFileError(err, flag) - } - - if flag&syscall.O_TRUNC != 0 { - err = syscall.Ftruncate(h, 0) - if err != nil { - syscall.CloseHandle(h) - return syscall.InvalidHandle, err - } - } - - return h, nil -} - -// ntCreateFileError maps error returns from NTCreateFile to user-visible errors. -func ntCreateFileError(err error, flag uint64) error { - s, ok := err.(NTStatus) - if !ok { - // Shouldn't really be possible, NtCreateFile always returns NTStatus. - return err - } - switch s { - case STATUS_REPARSE_POINT_ENCOUNTERED: - return syscall.ELOOP - case STATUS_NOT_A_DIRECTORY: - // ENOTDIR is the errno returned by open when O_DIRECTORY is specified - // and the target is not a directory. - // - // NtCreateFile can return STATUS_NOT_A_DIRECTORY under other circumstances, - // such as when opening "file/" where "file" is not a directory. - // (This might be Windows version dependent.) - // - // Only map STATUS_NOT_A_DIRECTORY to ENOTDIR when O_DIRECTORY is specified. - if flag&O_DIRECTORY != 0 { - return syscall.ENOTDIR - } - case STATUS_FILE_IS_A_DIRECTORY: - return syscall.EISDIR - case STATUS_OBJECT_NAME_COLLISION: - return syscall.EEXIST - } - return s.Errno() -} - -func Mkdirat(dirfd syscall.Handle, name string, mode uint32) error { - objAttrs := &OBJECT_ATTRIBUTES{} - if err := objAttrs.init(dirfd, name); err != nil { - return err - } - var h syscall.Handle - err := NtCreateFile( - &h, - FILE_GENERIC_READ, - objAttrs, - &IO_STATUS_BLOCK{}, - nil, - syscall.FILE_ATTRIBUTE_NORMAL, - syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE, - FILE_CREATE, - FILE_DIRECTORY_FILE, - nil, - 0, - ) - if err != nil { - return ntCreateFileError(err, 0) - } - syscall.CloseHandle(h) - return nil -} - -func Deleteat(dirfd syscall.Handle, name string, options uint32) error { - if name == "." { - // NtOpenFile's documentation isn't explicit about what happens when deleting ".". - // Make this an error consistent with that of POSIX. - return syscall.EINVAL - } - objAttrs := &OBJECT_ATTRIBUTES{} - if err := objAttrs.init(dirfd, name); err != nil { - return err - } - var h syscall.Handle - err := NtOpenFile( - &h, - SYNCHRONIZE|FILE_READ_ATTRIBUTES|DELETE, - objAttrs, - &IO_STATUS_BLOCK{}, - FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|options, - ) - if err != nil { - return ntCreateFileError(err, 0) - } - defer syscall.CloseHandle(h) - - if TestDeleteatFallback { - return deleteatFallback(h) - } - - const FileDispositionInformationEx = 64 - - // First, attempt to delete the file using POSIX semantics - // (which permit a file to be deleted while it is still open). - // This matches the behavior of DeleteFileW. - // - // The following call uses features available on different Windows versions: - // - FILE_DISPOSITION_INFORMATION_EX: Windows 10, version 1607 (aka RS1) - // - FILE_DISPOSITION_POSIX_SEMANTICS: Windows 10, version 1607 (aka RS1) - // - FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: Windows 10, version 1809 (aka RS5) - // - // Also, some file systems, like FAT32, don't support POSIX semantics. - err = NtSetInformationFile( - h, - &IO_STATUS_BLOCK{}, - unsafe.Pointer(&FILE_DISPOSITION_INFORMATION_EX{ - Flags: FILE_DISPOSITION_DELETE | - FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK | - FILE_DISPOSITION_POSIX_SEMANTICS | - // This differs from DeleteFileW, but matches os.Remove's - // behavior on Unix platforms of permitting deletion of - // read-only files. - FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, - }), - uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION_EX{})), - FileDispositionInformationEx, - ) - switch err { - case nil: - return nil - case STATUS_INVALID_INFO_CLASS, // the operating system doesn't support FileDispositionInformationEx - STATUS_INVALID_PARAMETER, // the operating system doesn't support one of the flags - STATUS_NOT_SUPPORTED: // the file system doesn't support FILE_DISPOSITION_INFORMATION_EX or one of the flags - return deleteatFallback(h) - default: - return err.(NTStatus).Errno() - } -} - -// TestDeleteatFallback should only be used for testing purposes. -// When set, [Deleteat] uses the fallback path unconditionally. -var TestDeleteatFallback bool - -// deleteatFallback is a deleteat implementation that strives -// for compatibility with older Windows versions and file systems -// over performance. -func deleteatFallback(h syscall.Handle) error { - var data syscall.ByHandleFileInformation - if err := syscall.GetFileInformationByHandle(h, &data); err == nil && data.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { - // Remove read-only attribute. Reopen the file, as it was previously open without FILE_WRITE_ATTRIBUTES access - // in order to maximize compatibility in the happy path. - wh, err := ReOpenFile(h, - FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, - ) - if err != nil { - return err - } - err = SetFileInformationByHandle( - wh, - FileBasicInfo, - unsafe.Pointer(&FILE_BASIC_INFO{ - FileAttributes: data.FileAttributes &^ FILE_ATTRIBUTE_READONLY, - }), - uint32(unsafe.Sizeof(FILE_BASIC_INFO{})), - ) - syscall.CloseHandle(wh) - if err != nil { - return err - } - } - - return SetFileInformationByHandle( - h, - FileDispositionInfo, - unsafe.Pointer(&FILE_DISPOSITION_INFO{ - DeleteFile: true, - }), - uint32(unsafe.Sizeof(FILE_DISPOSITION_INFO{})), - ) -} - -func Renameat(olddirfd syscall.Handle, oldpath string, newdirfd syscall.Handle, newpath string) error { - objAttrs := &OBJECT_ATTRIBUTES{} - if err := objAttrs.init(olddirfd, oldpath); err != nil { - return err - } - var h syscall.Handle - err := NtOpenFile( - &h, - SYNCHRONIZE|DELETE, - objAttrs, - &IO_STATUS_BLOCK{}, - FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT, - ) - if err != nil { - return ntCreateFileError(err, 0) - } - defer syscall.CloseHandle(h) - - renameInfoEx := FILE_RENAME_INFORMATION_EX{ - Flags: FILE_RENAME_REPLACE_IF_EXISTS | - FILE_RENAME_POSIX_SEMANTICS, - RootDirectory: newdirfd, - } - p16, err := syscall.UTF16FromString(newpath) - if err != nil { - return err - } - if len(p16) > len(renameInfoEx.FileName) { - return syscall.EINVAL - } - copy(renameInfoEx.FileName[:], p16) - renameInfoEx.FileNameLength = uint32((len(p16) - 1) * 2) - - const ( - FileRenameInformation = 10 - FileRenameInformationEx = 65 - ) - err = NtSetInformationFile( - h, - &IO_STATUS_BLOCK{}, - unsafe.Pointer(&renameInfoEx), - uint32(unsafe.Sizeof(FILE_RENAME_INFORMATION_EX{})), - FileRenameInformationEx, - ) - if err == nil { - return nil - } - - // If the prior rename failed, the filesystem might not support - // POSIX semantics (for example, FAT), or might not have implemented - // FILE_RENAME_INFORMATION_EX. - // - // Try again. - renameInfo := FILE_RENAME_INFORMATION{ - ReplaceIfExists: true, - RootDirectory: newdirfd, - } - copy(renameInfo.FileName[:], p16) - renameInfo.FileNameLength = renameInfoEx.FileNameLength - - err = NtSetInformationFile( - h, - &IO_STATUS_BLOCK{}, - unsafe.Pointer(&renameInfo), - uint32(unsafe.Sizeof(FILE_RENAME_INFORMATION{})), - FileRenameInformation, - ) - if st, ok := err.(NTStatus); ok { - return st.Errno() - } - return err -} - -func Linkat(olddirfd syscall.Handle, oldpath string, newdirfd syscall.Handle, newpath string) error { - objAttrs := &OBJECT_ATTRIBUTES{} - if err := objAttrs.init(olddirfd, oldpath); err != nil { - return err - } - var h syscall.Handle - err := NtOpenFile( - &h, - SYNCHRONIZE|FILE_WRITE_ATTRIBUTES, - objAttrs, - &IO_STATUS_BLOCK{}, - FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, - FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT, - ) - if err != nil { - return ntCreateFileError(err, 0) - } - defer syscall.CloseHandle(h) - - linkInfo := FILE_LINK_INFORMATION{ - RootDirectory: newdirfd, - } - p16, err := syscall.UTF16FromString(newpath) - if err != nil { - return err - } - if len(p16) > len(linkInfo.FileName) { - return syscall.EINVAL - } - copy(linkInfo.FileName[:], p16) - linkInfo.FileNameLength = uint32((len(p16) - 1) * 2) - - const ( - FileLinkInformation = 11 - ) - err = NtSetInformationFile( - h, - &IO_STATUS_BLOCK{}, - unsafe.Pointer(&linkInfo), - uint32(unsafe.Sizeof(FILE_LINK_INFORMATION{})), - FileLinkInformation, - ) - if st, ok := err.(NTStatus); ok { - return st.Errno() - } - return err -} - -// SymlinkatFlags configure Symlinkat. -// -// Symbolic links have two properties: They may be directory or file links, -// and they may be absolute or relative. -// -// The Windows API defines flags describing these properties -// (SYMBOLIC_LINK_FLAG_DIRECTORY and SYMLINK_FLAG_RELATIVE), -// but the flags are passed to different system calls and -// do not have distinct values, so we define our own enumeration -// that permits expressing both. -type SymlinkatFlags uint - -const ( - SYMLINKAT_DIRECTORY = SymlinkatFlags(1 << iota) - SYMLINKAT_RELATIVE -) - -func Symlinkat(oldname string, newdirfd syscall.Handle, newname string, flags SymlinkatFlags) error { - // Temporarily acquire symlink-creating privileges if possible. - // This is the behavior of CreateSymbolicLinkW. - // - // (When passed the SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag, - // CreateSymbolicLinkW ignores errors in acquiring privileges, as we do here.) - return withPrivilege("SeCreateSymbolicLinkPrivilege", func() error { - return symlinkat(oldname, newdirfd, newname, flags) - }) -} - -func symlinkat(oldname string, newdirfd syscall.Handle, newname string, flags SymlinkatFlags) error { - oldnameu16, err := syscall.UTF16FromString(oldname) - if err != nil { - return err - } - oldnameu16 = oldnameu16[:len(oldnameu16)-1] // trim off terminal NUL - - var options uint32 - if flags&SYMLINKAT_DIRECTORY != 0 { - options |= FILE_DIRECTORY_FILE - } else { - options |= FILE_NON_DIRECTORY_FILE - } - - objAttrs := &OBJECT_ATTRIBUTES{} - if err := objAttrs.init(newdirfd, newname); err != nil { - return err - } - var h syscall.Handle - err = NtCreateFile( - &h, - SYNCHRONIZE|FILE_WRITE_ATTRIBUTES|DELETE, - objAttrs, - &IO_STATUS_BLOCK{}, - nil, - syscall.FILE_ATTRIBUTE_NORMAL, - 0, - FILE_CREATE, - FILE_OPEN_REPARSE_POINT|FILE_OPEN_FOR_BACKUP_INTENT|FILE_SYNCHRONOUS_IO_NONALERT|options, - nil, - 0, - ) - if err != nil { - return ntCreateFileError(err, 0) - } - defer syscall.CloseHandle(h) - - // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_reparse_data_buffer - type reparseDataBufferT struct { - _ structs.HostLayout - - ReparseTag uint32 - ReparseDataLength uint16 - Reserved uint16 - - SubstituteNameOffset uint16 - SubstituteNameLength uint16 - PrintNameOffset uint16 - PrintNameLength uint16 - Flags uint32 - } - - const ( - headerSize = uint16(unsafe.Offsetof(reparseDataBufferT{}.SubstituteNameOffset)) - bufferSize = uint16(unsafe.Sizeof(reparseDataBufferT{})) - ) - - // Data buffer containing a SymbolicLinkReparseBuffer followed by the link target. - rdbbuf := make([]byte, bufferSize+uint16(2*len(oldnameu16))) - - rdb := (*reparseDataBufferT)(unsafe.Pointer(&rdbbuf[0])) - rdb.ReparseTag = syscall.IO_REPARSE_TAG_SYMLINK - rdb.ReparseDataLength = uint16(len(rdbbuf)) - uint16(headerSize) - rdb.SubstituteNameOffset = 0 - rdb.SubstituteNameLength = uint16(2 * len(oldnameu16)) - rdb.PrintNameOffset = 0 - rdb.PrintNameLength = rdb.SubstituteNameLength - if flags&SYMLINKAT_RELATIVE != 0 { - rdb.Flags = SYMLINK_FLAG_RELATIVE - } - - namebuf := rdbbuf[bufferSize:] - copy(namebuf, unsafe.String((*byte)(unsafe.Pointer(&oldnameu16[0])), 2*len(oldnameu16))) - - err = syscall.DeviceIoControl( - h, - FSCTL_SET_REPARSE_POINT, - &rdbbuf[0], - uint32(len(rdbbuf)), - nil, - 0, - nil, - nil) - if err != nil { - // Creating the symlink has failed, so try to remove the file. - const FileDispositionInformation = 13 - NtSetInformationFile( - h, - &IO_STATUS_BLOCK{}, - unsafe.Pointer(&FILE_DISPOSITION_INFORMATION{ - DeleteFile: true, - }), - uint32(unsafe.Sizeof(FILE_DISPOSITION_INFORMATION{})), - FileDispositionInformation, - ) - return err - } - - return nil -} - -// withPrivilege temporariliy acquires the named privilege and runs f. -// If the privilege cannot be acquired it runs f anyway, -// which should fail with an appropriate error. -func withPrivilege(privilege string, f func() error) error { - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err := ImpersonateSelf(SecurityImpersonation) - if err != nil { - return f() - } - defer RevertToSelf() - - curThread, err := GetCurrentThread() - if err != nil { - return f() - } - var token syscall.Token - err = OpenThreadToken(curThread, syscall.TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, false, &token) - if err != nil { - return f() - } - defer syscall.CloseHandle(syscall.Handle(token)) - - privStr, err := syscall.UTF16PtrFromString(privilege) - if err != nil { - return f() - } - var tokenPriv TOKEN_PRIVILEGES - err = LookupPrivilegeValue(nil, privStr, &tokenPriv.Privileges[0].Luid) - if err != nil { - return f() - } - - tokenPriv.PrivilegeCount = 1 - tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED - err = AdjustTokenPrivileges(token, false, &tokenPriv, 0, nil, nil) - if err != nil { - return f() - } - - return f() -} diff --git a/testing/internal/syscall/windows/at_windows_test.go b/testing/internal/syscall/windows/at_windows_test.go deleted file mode 100644 index 325a2915..00000000 --- a/testing/internal/syscall/windows/at_windows_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024 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 windows_test - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows" - "os" - "path/filepath" - "syscall" - "testing" -) - -func TestOpen(t *testing.T) { - t.Parallel() - - dir := t.TempDir() - file := filepath.Join(dir, "a") - f, err := os.Create(file) - if err != nil { - t.Fatal(err) - } - f.Close() - - tests := []struct { - path string - flag int - err error - }{ - {dir, syscall.O_RDONLY, nil}, - {dir, syscall.O_CREAT, nil}, - {dir, syscall.O_RDONLY | syscall.O_CREAT, nil}, - {file, syscall.O_APPEND | syscall.O_WRONLY | os.O_CREATE, nil}, - {file, syscall.O_APPEND | syscall.O_WRONLY | os.O_CREATE | os.O_TRUNC, nil}, - {dir, syscall.O_RDONLY | syscall.O_TRUNC, syscall.ERROR_ACCESS_DENIED}, - {dir, syscall.O_WRONLY | syscall.O_RDWR, nil}, // TODO: syscall.Open returns EISDIR here, we should reconcile this - {dir, syscall.O_WRONLY, syscall.EISDIR}, - {dir, syscall.O_RDWR, syscall.EISDIR}, - } - for i, tt := range tests { - dir := filepath.Dir(tt.path) - dirfd, err := syscall.Open(dir, syscall.O_RDONLY, 0) - if err != nil { - t.Error(err) - continue - } - base := filepath.Base(tt.path) - h, err := windows.Openat(dirfd, base, uint64(tt.flag), 0o660) - syscall.CloseHandle(dirfd) - if err == nil { - syscall.CloseHandle(h) - } - if err != tt.err { - t.Errorf("%d: Open got %q, want %q", i, err, tt.err) - } - } -} diff --git a/testing/internal/syscall/windows/exec_windows_test.go b/testing/internal/syscall/windows/exec_windows_test.go deleted file mode 100644 index a75e838f..00000000 --- a/testing/internal/syscall/windows/exec_windows_test.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2017 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 windows - -package windows_test - -import ( - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "syscall" - "testing" - "unsafe" -) - -func TestRunAtLowIntegrity(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - wil, err := getProcessIntegrityLevel() - if err != nil { - fmt.Fprintf(os.Stderr, "error: %s\n", err.Error()) - os.Exit(9) - return - } - fmt.Printf("%s", wil) - os.Exit(0) - return - } - - cmd := exec.Command(testenv.Executable(t), "-test.run=^TestRunAtLowIntegrity$", "--") - cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} - - token, err := getIntegrityLevelToken(sidWilLow) - if err != nil { - t.Fatal(err) - } - defer token.Close() - - cmd.SysProcAttr = &syscall.SysProcAttr{ - Token: token, - } - - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatal(err) - } - - if string(out) != sidWilLow { - t.Fatalf("Child process did not run as low integrity level: %s", string(out)) - } -} - -const ( - sidWilLow = `S-1-16-4096` -) - -func getProcessIntegrityLevel() (string, error) { - procToken, err := syscall.OpenCurrentProcessToken() - if err != nil { - return "", err - } - defer procToken.Close() - - p, err := tokenGetInfo(procToken, syscall.TokenIntegrityLevel, 64) - if err != nil { - return "", err - } - - tml := (*windows.TOKEN_MANDATORY_LABEL)(p) - - sid := (*syscall.SID)(unsafe.Pointer(tml.Label.Sid)) - - return sid.String() -} - -func tokenGetInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) { - n := uint32(initSize) - for { - b := make([]byte, n) - e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) - if e == nil { - return unsafe.Pointer(&b[0]), nil - } - if e != syscall.ERROR_INSUFFICIENT_BUFFER { - return nil, e - } - if n <= uint32(len(b)) { - return nil, e - } - } -} - -func getIntegrityLevelToken(wns string) (syscall.Token, error) { - var procToken, token syscall.Token - - proc, err := syscall.GetCurrentProcess() - if err != nil { - return 0, err - } - defer syscall.CloseHandle(proc) - - err = syscall.OpenProcessToken(proc, - syscall.TOKEN_DUPLICATE| - syscall.TOKEN_ADJUST_DEFAULT| - syscall.TOKEN_QUERY| - syscall.TOKEN_ASSIGN_PRIMARY, - &procToken) - if err != nil { - return 0, err - } - defer procToken.Close() - - sid, err := syscall.StringToSid(wns) - if err != nil { - return 0, err - } - - tml := &windows.TOKEN_MANDATORY_LABEL{} - tml.Label.Attributes = windows.SE_GROUP_INTEGRITY - tml.Label.Sid = sid - - err = windows.DuplicateTokenEx(procToken, 0, nil, windows.SecurityImpersonation, - windows.TokenPrimary, &token) - if err != nil { - return 0, err - } - - err = windows.SetTokenInformation(token, - syscall.TokenIntegrityLevel, - unsafe.Pointer(tml), - tml.Size()) - if err != nil { - token.Close() - return 0, err - } - return token, nil -} diff --git a/testing/internal/syscall/windows/memory_windows.go b/testing/internal/syscall/windows/memory_windows.go deleted file mode 100644 index 8fb34cf3..00000000 --- a/testing/internal/syscall/windows/memory_windows.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2017 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 windows - -type MemoryBasicInformation struct { - // A pointer to the base address of the region of pages. - BaseAddress uintptr - // A pointer to the base address of a range of pages allocated by the VirtualAlloc function. - // The page pointed to by the BaseAddress member is contained within this allocation range. - AllocationBase uintptr - // The memory protection option when the region was initially allocated - AllocationProtect uint32 - PartitionId uint16 - // The size of the region beginning at the base address in which all pages have identical attributes, in bytes. - RegionSize uintptr - // The state of the pages in the region. - State uint32 - // The access protection of the pages in the region. - Protect uint32 - // The type of pages in the region. - Type uint32 -} diff --git a/testing/internal/syscall/windows/mksyscall.go b/testing/internal/syscall/windows/mksyscall.go deleted file mode 100644 index f97ab526..00000000 --- a/testing/internal/syscall/windows/mksyscall.go +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -//go:build generate - -package windows - -//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go version_windows.go diff --git a/testing/internal/syscall/windows/net_windows.go b/testing/internal/syscall/windows/net_windows.go deleted file mode 100644 index 023ddaaa..00000000 --- a/testing/internal/syscall/windows/net_windows.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2021 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 windows - -import ( - "syscall" - _ "unsafe" -) - -//go:linkname WSASendtoInet4 syscall.wsaSendtoInet4 -//go:noescape -func WSASendtoInet4(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet4, overlapped *syscall.Overlapped, croutine *byte) (err error) - -//go:linkname WSASendtoInet6 syscall.wsaSendtoInet6 -//go:noescape -func WSASendtoInet6(s syscall.Handle, bufs *syscall.WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *syscall.SockaddrInet6, overlapped *syscall.Overlapped, croutine *byte) (err error) - -const ( - SO_TYPE = 0x1008 - SIO_TCP_INITIAL_RTO = syscall.IOC_IN | syscall.IOC_VENDOR | 17 - TCP_INITIAL_RTO_UNSPECIFIED_RTT = ^uint16(0) - TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS = ^uint8(1) -) - -type TCP_INITIAL_RTO_PARAMETERS struct { - Rtt uint16 - MaxSynRetransmissions uint8 -} diff --git a/testing/internal/syscall/windows/nonblocking_windows.go b/testing/internal/syscall/windows/nonblocking_windows.go deleted file mode 100644 index ec6f520a..00000000 --- a/testing/internal/syscall/windows/nonblocking_windows.go +++ /dev/null @@ -1,21 +0,0 @@ -// 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. - -package windows - -import ( - "syscall" - "unsafe" -) - -// IsNonblock returns whether the file descriptor fd is opened -// in non-blocking mode, that is, the [syscall.FILE_FLAG_OVERLAPPED] flag -// was set when the file was opened. -func IsNonblock(fd syscall.Handle) (nonblocking bool, err error) { - var info FILE_MODE_INFORMATION - if err := NtQueryInformationFile(syscall.Handle(fd), &IO_STATUS_BLOCK{}, unsafe.Pointer(&info), uint32(unsafe.Sizeof(info)), FileModeInformation); err != nil { - return false, err - } - return info.Mode&(FILE_SYNCHRONOUS_IO_ALERT|FILE_SYNCHRONOUS_IO_NONALERT) == 0, nil -} diff --git a/testing/internal/syscall/windows/psapi_windows.go b/testing/internal/syscall/windows/psapi_windows.go deleted file mode 100644 index b138e658..00000000 --- a/testing/internal/syscall/windows/psapi_windows.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 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 windows - -type PROCESS_MEMORY_COUNTERS struct { - CB uint32 - PageFaultCount uint32 - PeakWorkingSetSize uintptr - WorkingSetSize uintptr - QuotaPeakPagedPoolUsage uintptr - QuotaPagedPoolUsage uintptr - QuotaPeakNonPagedPoolUsage uintptr - QuotaNonPagedPoolUsage uintptr - PagefileUsage uintptr - PeakPagefileUsage uintptr -} - -//sys GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) = psapi.GetProcessMemoryInfo diff --git a/testing/internal/syscall/windows/registry/export_test.go b/testing/internal/syscall/windows/registry/export_test.go deleted file mode 100644 index 7f1ac70e..00000000 --- a/testing/internal/syscall/windows/registry/export_test.go +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -//go:build windows - -package registry - -func (k Key) SetValue(name string, valtype uint32, data []byte) error { - return k.setValue(name, valtype, data) -} diff --git a/testing/internal/syscall/windows/registry/key.go b/testing/internal/syscall/windows/registry/key.go deleted file mode 100644 index b95fa8d3..00000000 --- a/testing/internal/syscall/windows/registry/key.go +++ /dev/null @@ -1,168 +0,0 @@ -// 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. - -//go:build windows - -// Package registry provides access to the Windows registry. -// -// Here is a simple example, opening a registry key and reading a string value from it. -// -// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) -// if err != nil { -// log.Fatal(err) -// } -// defer k.Close() -// -// s, _, err := k.GetStringValue("SystemRoot") -// if err != nil { -// log.Fatal(err) -// } -// fmt.Printf("Windows system root is %q\n", s) -// -// NOTE: This package is a copy of golang.org/x/sys/windows/registry -// with KeyInfo.ModTime removed to prevent dependency cycles. -package registry - -import ( - "runtime" - "syscall" -) - -const ( - // Registry key security and access rights. - // See https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights - // for details. - ALL_ACCESS = 0xf003f - CREATE_LINK = 0x00020 - CREATE_SUB_KEY = 0x00004 - ENUMERATE_SUB_KEYS = 0x00008 - EXECUTE = 0x20019 - NOTIFY = 0x00010 - QUERY_VALUE = 0x00001 - READ = 0x20019 - SET_VALUE = 0x00002 - WOW64_32KEY = 0x00200 - WOW64_64KEY = 0x00100 - WRITE = 0x20006 -) - -// Key is a handle to an open Windows registry key. -// Keys can be obtained by calling OpenKey; there are -// also some predefined root keys such as CURRENT_USER. -// Keys can be used directly in the Windows API. -type Key syscall.Handle - -const ( - // Windows defines some predefined root keys that are always open. - // An application can use these keys as entry points to the registry. - // Normally these keys are used in OpenKey to open new keys, - // but they can also be used anywhere a Key is required. - CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT) - CURRENT_USER = Key(syscall.HKEY_CURRENT_USER) - LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE) - USERS = Key(syscall.HKEY_USERS) - CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG) -) - -// Close closes open key k. -func (k Key) Close() error { - return syscall.RegCloseKey(syscall.Handle(k)) -} - -// OpenKey opens a new key with path name relative to key k. -// It accepts any open key, including CURRENT_USER and others, -// and returns the new key and an error. -// The access parameter specifies desired access rights to the -// key to be opened. -func OpenKey(k Key, path string, access uint32) (Key, error) { - p, err := syscall.UTF16PtrFromString(path) - if err != nil { - return 0, err - } - var subkey syscall.Handle - err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey) - if err != nil { - return 0, err - } - return Key(subkey), nil -} - -// ReadSubKeyNames returns the names of subkeys of key k. -func (k Key) ReadSubKeyNames() ([]string, error) { - // RegEnumKeyEx must be called repeatedly and to completion. - // During this time, this goroutine cannot migrate away from - // its current thread. See #49320. - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - names := make([]string, 0) - // Registry key size limit is 255 bytes and described there: - // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits - buf := make([]uint16, 256) //plus extra room for terminating zero byte -loopItems: - for i := uint32(0); ; i++ { - l := uint32(len(buf)) - for { - err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - return names, nil -} - -// CreateKey creates a key named path under open key k. -// CreateKey returns the new key and a boolean flag that reports -// whether the key already existed. -// The access parameter specifies the access rights for the key -// to be created. -func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { - var h syscall.Handle - var d uint32 - err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), - 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) - if err != nil { - return 0, false, err - } - return Key(h), d == _REG_OPENED_EXISTING_KEY, nil -} - -// DeleteKey deletes the subkey path of key k and its values. -func DeleteKey(k Key, path string) error { - return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) -} - -// A KeyInfo describes the statistics of a key. It is returned by Stat. -type KeyInfo struct { - SubKeyCount uint32 - MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte - ValueCount uint32 - MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte - MaxValueLen uint32 // longest data component among the key's values, in bytes - lastWriteTime syscall.Filetime -} - -// Stat retrieves information about the open key k. -func (k Key) Stat() (*KeyInfo, error) { - var ki KeyInfo - err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil, - &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount, - &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime) - if err != nil { - return nil, err - } - return &ki, nil -} diff --git a/testing/internal/syscall/windows/registry/mksyscall.go b/testing/internal/syscall/windows/registry/mksyscall.go deleted file mode 100644 index 0e0b4210..00000000 --- a/testing/internal/syscall/windows/registry/mksyscall.go +++ /dev/null @@ -1,9 +0,0 @@ -// 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. - -//go:build generate - -package registry - -//go:generate go run ../../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go diff --git a/testing/internal/syscall/windows/registry/registry_test.go b/testing/internal/syscall/windows/registry/registry_test.go deleted file mode 100644 index e6934990..00000000 --- a/testing/internal/syscall/windows/registry/registry_test.go +++ /dev/null @@ -1,652 +0,0 @@ -// 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. - -//go:build windows - -package registry_test - -import ( - "bytes" - "crypto/rand" - "os" - "slices" - "syscall" - "testing" - "unsafe" - - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows/registry" -) - -func randKeyName(prefix string) string { - const numbers = "0123456789" - buf := make([]byte, 10) - rand.Read(buf) - for i, b := range buf { - buf[i] = numbers[b%byte(len(numbers))] - } - return prefix + string(buf) -} - -func TestReadSubKeyNames(t *testing.T) { - k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS) - if err != nil { - t.Fatal(err) - } - defer k.Close() - - names, err := k.ReadSubKeyNames() - if err != nil { - t.Fatal(err) - } - var foundStdOle bool - for _, name := range names { - // Every PC has "stdole 2.0 OLE Automation" library installed. - if name == "{00020430-0000-0000-C000-000000000046}" { - foundStdOle = true - } - } - if !foundStdOle { - t.Fatal("could not find stdole 2.0 OLE Automation") - } -} - -func TestCreateOpenDeleteKey(t *testing.T) { - k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) - if err != nil { - t.Fatal(err) - } - defer k.Close() - - testKName := randKeyName("TestCreateOpenDeleteKey_") - - testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) - if err != nil { - t.Fatal(err) - } - defer testK.Close() - - if exist { - t.Fatalf("key %q already exists", testKName) - } - - testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) - if err != nil { - t.Fatal(err) - } - defer testKAgain.Close() - - if !exist { - t.Fatalf("key %q should already exist", testKName) - } - - testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) - if err != nil { - t.Fatal(err) - } - defer testKOpened.Close() - - err = registry.DeleteKey(k, testKName) - if err != nil { - t.Fatal(err) - } - - testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) - if err == nil { - defer testKOpenedAgain.Close() - t.Fatalf("key %q should already been deleted", testKName) - } - if err != registry.ErrNotExist { - t.Fatalf(`unexpected error ("not exist" expected): %v`, err) - } -} - -type ValueTest struct { - Type uint32 - Name string - Value any - WillFail bool -} - -var ValueTests = []ValueTest{ - {Type: registry.SZ, Name: "String1", Value: ""}, - {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true}, - {Type: registry.SZ, Name: "String3", Value: "Hello World"}, - {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true}, - {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""}, - {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true}, - {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"}, - {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true}, - {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"}, - {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"}, - {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."}, - {Type: registry.BINARY, Name: "Binary1", Value: []byte{}}, - {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}}, - {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}}, - {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)}, - {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)}, - {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)}, - {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)}, - {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)}, - {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)}, - {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)}, - {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)}, - {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)}, - {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)}, - {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}}, - {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}}, - {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}}, - {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}}, - {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true}, - {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true}, - {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true}, - {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true}, - {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true}, -} - -func setValues(t *testing.T, k registry.Key) { - for _, test := range ValueTests { - var err error - switch test.Type { - case registry.SZ: - err = k.SetStringValue(test.Name, test.Value.(string)) - case registry.EXPAND_SZ: - err = k.SetExpandStringValue(test.Name, test.Value.(string)) - case registry.MULTI_SZ: - err = k.SetStringsValue(test.Name, test.Value.([]string)) - case registry.BINARY: - err = k.SetBinaryValue(test.Name, test.Value.([]byte)) - case registry.DWORD: - err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64))) - case registry.QWORD: - err = k.SetQWordValue(test.Name, test.Value.(uint64)) - default: - t.Fatalf("unsupported type %d for %s value", test.Type, test.Name) - } - if test.WillFail { - if err == nil { - t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value) - } - } else { - if err != nil { - t.Fatal(err) - } - } - } -} - -func enumerateValues(t *testing.T, k registry.Key) { - names, err := k.ReadValueNames() - if err != nil { - t.Error(err) - return - } - haveNames := make(map[string]bool) - for _, n := range names { - haveNames[n] = false - } - for _, test := range ValueTests { - wantFound := !test.WillFail - _, haveFound := haveNames[test.Name] - if wantFound && !haveFound { - t.Errorf("value %s is not found while enumerating", test.Name) - } - if haveFound && !wantFound { - t.Errorf("value %s is found while enumerating, but expected to fail", test.Name) - } - if haveFound { - delete(haveNames, test.Name) - } - } - for n, v := range haveNames { - t.Errorf("value %s (%v) is found while enumerating, but has not been created", n, v) - } -} - -func testErrNotExist(t *testing.T, name string, err error) { - if err == nil { - t.Errorf("%s value should not exist", name) - return - } - if err != registry.ErrNotExist { - t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err) - return - } -} - -func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) { - if err == nil { - t.Errorf("GetXValue(%q) should not succeed", test.Name) - return - } - if err != registry.ErrUnexpectedType { - t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } -} - -func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) { - got, gottype, err := k.GetStringValue(test.Name) - if err != nil { - t.Errorf("GetStringValue(%s) failed: %v", test.Name, err) - return - } - if got != test.Value { - t.Errorf("want %s value %q, got %q", test.Name, test.Value, got) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } - if gottype == registry.EXPAND_SZ { - _, err = registry.ExpandString(got) - if err != nil { - t.Errorf("ExpandString(%s) failed: %v", got, err) - return - } - } -} - -func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) { - got, gottype, err := k.GetIntegerValue(test.Name) - if err != nil { - t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err) - return - } - if got != test.Value.(uint64) { - t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } -} - -func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) { - got, gottype, err := k.GetBinaryValue(test.Name) - if err != nil { - t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err) - return - } - if !bytes.Equal(got, test.Value.([]byte)) { - t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } -} - -func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) { - got, gottype, err := k.GetStringsValue(test.Name) - if err != nil { - t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err) - return - } - if !slices.Equal(got, test.Value.([]string)) { - t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } -} - -func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) { - if size <= 0 { - return - } - // read data with no buffer - gotsize, gottype, err := k.GetValue(test.Name, nil) - if err != nil { - t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) - return - } - if gotsize != size { - t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } - // read data with short buffer - gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1)) - if err == nil { - t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1) - return - } - if err != registry.ErrShortBuffer { - t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err) - return - } - if gotsize != size { - t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } - // read full data - gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size)) - if err != nil { - t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) - return - } - if gotsize != size { - t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) - return - } - if gottype != test.Type { - t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) - return - } - // check GetValue returns ErrNotExist as required - _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size)) - if err == nil { - t.Errorf("GetValue(%q) should not succeed", test.Name) - return - } - if err != registry.ErrNotExist { - t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err) - return - } -} - -func testValues(t *testing.T, k registry.Key) { - for _, test := range ValueTests { - switch test.Type { - case registry.SZ, registry.EXPAND_SZ: - if test.WillFail { - _, _, err := k.GetStringValue(test.Name) - testErrNotExist(t, test.Name, err) - } else { - testGetStringValue(t, k, test) - _, gottype, err := k.GetIntegerValue(test.Name) - testErrUnexpectedType(t, test, gottype, err) - // Size of utf16 string in bytes is not perfect, - // but correct for current test values. - // Size also includes terminating 0. - testGetValue(t, k, test, (len(test.Value.(string))+1)*2) - } - _, _, err := k.GetStringValue(test.Name + "_string_not_created") - testErrNotExist(t, test.Name+"_string_not_created", err) - case registry.DWORD, registry.QWORD: - testGetIntegerValue(t, k, test) - _, gottype, err := k.GetBinaryValue(test.Name) - testErrUnexpectedType(t, test, gottype, err) - _, _, err = k.GetIntegerValue(test.Name + "_int_not_created") - testErrNotExist(t, test.Name+"_int_not_created", err) - size := 8 - if test.Type == registry.DWORD { - size = 4 - } - testGetValue(t, k, test, size) - case registry.BINARY: - testGetBinaryValue(t, k, test) - _, gottype, err := k.GetStringsValue(test.Name) - testErrUnexpectedType(t, test, gottype, err) - _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created") - testErrNotExist(t, test.Name+"_byte_not_created", err) - testGetValue(t, k, test, len(test.Value.([]byte))) - case registry.MULTI_SZ: - if test.WillFail { - _, _, err := k.GetStringsValue(test.Name) - testErrNotExist(t, test.Name, err) - } else { - testGetStringsValue(t, k, test) - _, gottype, err := k.GetStringValue(test.Name) - testErrUnexpectedType(t, test, gottype, err) - size := 0 - for _, s := range test.Value.([]string) { - size += len(s) + 1 // nil terminated - } - size += 1 // extra nil at the end - size *= 2 // count bytes, not uint16 - testGetValue(t, k, test, size) - } - _, _, err := k.GetStringsValue(test.Name + "_strings_not_created") - testErrNotExist(t, test.Name+"_strings_not_created", err) - default: - t.Errorf("unsupported type %d for %s value", test.Type, test.Name) - continue - } - } -} - -func testStat(t *testing.T, k registry.Key) { - subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY) - if err != nil { - t.Error(err) - return - } - defer subk.Close() - - defer registry.DeleteKey(k, "subkey") - - ki, err := k.Stat() - if err != nil { - t.Error(err) - return - } - if ki.SubKeyCount != 1 { - t.Error("key must have 1 subkey") - } - if ki.MaxSubKeyLen != 6 { - t.Error("key max subkey name length must be 6") - } - if ki.ValueCount != 24 { - t.Errorf("key must have 24 values, but is %d", ki.ValueCount) - } - if ki.MaxValueNameLen != 12 { - t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen) - } - if ki.MaxValueLen != 38 { - t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen) - } -} - -func deleteValues(t *testing.T, k registry.Key) { - for _, test := range ValueTests { - if test.WillFail { - continue - } - err := k.DeleteValue(test.Name) - if err != nil { - t.Error(err) - continue - } - } - names, err := k.ReadValueNames() - if err != nil { - t.Error(err) - return - } - if len(names) != 0 { - t.Errorf("some values remain after deletion: %v", names) - } -} - -func TestValues(t *testing.T) { - softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) - if err != nil { - t.Fatal(err) - } - defer softwareK.Close() - - testKName := randKeyName("TestValues_") - - k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) - if err != nil { - t.Fatal(err) - } - defer k.Close() - - if exist { - t.Fatalf("key %q already exists", testKName) - } - - defer registry.DeleteKey(softwareK, testKName) - - setValues(t, k) - - enumerateValues(t, k) - - testValues(t, k) - - testStat(t, k) - - deleteValues(t, k) -} - -func TestExpandString(t *testing.T) { - got, err := registry.ExpandString("%PATH%") - if err != nil { - t.Fatal(err) - } - want := os.Getenv("PATH") - if got != want { - t.Errorf("want %q string expanded, got %q", want, got) - } -} - -func TestInvalidValues(t *testing.T) { - softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) - if err != nil { - t.Fatal(err) - } - defer softwareK.Close() - - testKName := randKeyName("TestInvalidValues_") - - k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) - if err != nil { - t.Fatal(err) - } - defer k.Close() - - if exist { - t.Fatalf("key %q already exists", testKName) - } - - defer registry.DeleteKey(softwareK, testKName) - - var tests = []struct { - Type uint32 - Name string - Data []byte - }{ - {registry.DWORD, "Dword1", nil}, - {registry.DWORD, "Dword2", []byte{1, 2, 3}}, - {registry.QWORD, "Qword1", nil}, - {registry.QWORD, "Qword2", []byte{1, 2, 3}}, - {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, - {registry.MULTI_SZ, "MultiString1", nil}, - {registry.MULTI_SZ, "MultiString2", []byte{0}}, - {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, - {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, - {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, - } - - for _, test := range tests { - err := k.SetValue(test.Name, test.Type, test.Data) - if err != nil { - t.Fatalf("SetValue for %q failed: %v", test.Name, err) - } - } - - for _, test := range tests { - switch test.Type { - case registry.DWORD, registry.QWORD: - value, valType, err := k.GetIntegerValue(test.Name) - if err == nil { - t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) - } - case registry.MULTI_SZ: - value, valType, err := k.GetStringsValue(test.Name) - if err == nil { - if len(value) != 0 { - t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) - } - } - default: - t.Errorf("unsupported type %d for %s value", test.Type, test.Name) - } - } -} - -func TestGetMUIStringValue(t *testing.T) { - var dtzi DynamicTimezoneinformation - if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil { - t.Fatal(err) - } - tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:]) - timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE, - `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ) - if err != nil { - t.Fatal(err) - } - defer timezoneK.Close() - - type testType struct { - name string - want string - } - var tests = []testType{ - {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])}, - } - if dtzi.DynamicDaylightTimeDisabled == 0 { - tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])}) - } - - for _, test := range tests { - got, err := timezoneK.GetMUIStringValue(test.name) - if err != nil { - t.Error("GetMUIStringValue:", err) - } - - if got != test.want { - t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want) - } - } -} - -type DynamicTimezoneinformation struct { - Bias int32 - StandardName [32]uint16 - StandardDate syscall.Systemtime - StandardBias int32 - DaylightName [32]uint16 - DaylightDate syscall.Systemtime - DaylightBias int32 - TimeZoneKeyName [128]uint16 - DynamicDaylightTimeDisabled uint8 -} - -var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - - procGetDynamicTimeZoneInformation = modkernel32.NewProc("GetDynamicTimeZoneInformation") -) - -func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0) - rc = uint32(r0) - if rc == 0xffffffff { - if e1 != 0 { - err = error(e1) - } else { - err = syscall.EINVAL - } - } - return -} diff --git a/testing/internal/syscall/windows/registry/syscall.go b/testing/internal/syscall/windows/registry/syscall.go deleted file mode 100644 index 8e730916..00000000 --- a/testing/internal/syscall/windows/registry/syscall.go +++ /dev/null @@ -1,27 +0,0 @@ -// 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. - -//go:build windows - -package registry - -import "syscall" - -const ( - _REG_OPTION_NON_VOLATILE = 0 - - _REG_CREATED_NEW_KEY = 1 - _REG_OPENED_EXISTING_KEY = 2 - - _ERROR_NO_MORE_ITEMS syscall.Errno = 259 -) - -//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW -//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW -//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW -//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW -//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW -//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW - -//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW diff --git a/testing/internal/syscall/windows/registry/value.go b/testing/internal/syscall/windows/registry/value.go deleted file mode 100644 index 67b1144e..00000000 --- a/testing/internal/syscall/windows/registry/value.go +++ /dev/null @@ -1,369 +0,0 @@ -// 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. - -//go:build windows - -package registry - -import ( - "errors" - "syscall" - "unicode/utf16" - "unsafe" -) - -const ( - // Registry value types. - NONE = 0 - SZ = 1 - EXPAND_SZ = 2 - BINARY = 3 - DWORD = 4 - DWORD_BIG_ENDIAN = 5 - LINK = 6 - MULTI_SZ = 7 - RESOURCE_LIST = 8 - FULL_RESOURCE_DESCRIPTOR = 9 - RESOURCE_REQUIREMENTS_LIST = 10 - QWORD = 11 -) - -var ( - // ErrShortBuffer is returned when the buffer was too short for the operation. - ErrShortBuffer = syscall.ERROR_MORE_DATA - - // ErrNotExist is returned when a registry key or value does not exist. - ErrNotExist = syscall.ERROR_FILE_NOT_FOUND - - // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. - ErrUnexpectedType = errors.New("unexpected key value type") -) - -// GetValue retrieves the type and data for the specified value associated -// with an open key k. It fills up buffer buf and returns the retrieved -// byte count n. If buf is too small to fit the stored value it returns -// ErrShortBuffer error along with the required buffer size n. -// If no buffer is provided, it returns true and actual buffer size n. -// If no buffer is provided, GetValue returns the value's type only. -// If the value does not exist, the error returned is ErrNotExist. -// -// GetValue is a low level function. If value's type is known, use the appropriate -// Get*Value function instead. -func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return 0, 0, err - } - var pbuf *byte - if len(buf) > 0 { - pbuf = (*byte)(unsafe.Pointer(&buf[0])) - } - l := uint32(len(buf)) - err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) - if err != nil { - return int(l), valtype, err - } - return int(l), valtype, nil -} - -func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return nil, 0, err - } - var t uint32 - n := uint32(len(buf)) - for { - err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) - if err == nil { - return buf[:n], t, nil - } - if err != syscall.ERROR_MORE_DATA { - return nil, 0, err - } - if n <= uint32(len(buf)) { - return nil, 0, err - } - buf = make([]byte, n) - } -} - -// GetStringValue retrieves the string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringValue returns ErrNotExist. -// If value is not SZ or EXPAND_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return "", typ, err2 - } - switch typ { - case SZ, EXPAND_SZ: - default: - return "", typ, ErrUnexpectedType - } - if len(data) == 0 { - return "", typ, nil - } - u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2] - return syscall.UTF16ToString(u), typ, nil -} - -// GetMUIStringValue retrieves the localized string value for -// the specified value name associated with an open key k. -// If the value name doesn't exist or the localized string value -// can't be resolved, GetMUIStringValue returns ErrNotExist. -func (k Key) GetMUIStringValue(name string) (string, error) { - pname, err := syscall.UTF16PtrFromString(name) - if err != nil { - return "", err - } - - buf := make([]uint16, 1024) - var buflen uint32 - var pdir *uint16 - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path - - // Try to resolve the string value using the system directory as - // a DLL search path; this assumes the string value is of the form - // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320. - - // This approach works with tzres.dll but may have to be revised - // in the future to allow callers to provide custom search paths. - - var s string - s, err = ExpandString("%SystemRoot%\\system32\\") - if err != nil { - return "", err - } - pdir, err = syscall.UTF16PtrFromString(s) - if err != nil { - return "", err - } - - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed - if buflen <= uint32(len(buf)) { - break // Buffer not growing, assume race; break - } - buf = make([]uint16, buflen) - err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir) - } - - if err != nil { - return "", err - } - - return syscall.UTF16ToString(buf), nil -} - -// ExpandString expands environment-variable strings and replaces -// them with the values defined for the current user. -// Use ExpandString to expand EXPAND_SZ strings. -func ExpandString(value string) (string, error) { - if value == "" { - return "", nil - } - p, err := syscall.UTF16PtrFromString(value) - if err != nil { - return "", err - } - r := make([]uint16, 100) - for { - n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) - if err != nil { - return "", err - } - if n <= uint32(len(r)) { - return syscall.UTF16ToString(r[:n]), nil - } - r = make([]uint16, n) - } -} - -// GetStringsValue retrieves the []string value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetStringsValue returns ErrNotExist. -// If value is not MULTI_SZ, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != MULTI_SZ { - return nil, typ, ErrUnexpectedType - } - if len(data) == 0 { - return nil, typ, nil - } - p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[: len(data)/2 : len(data)/2] - if len(p) == 0 { - return nil, typ, nil - } - if p[len(p)-1] == 0 { - p = p[:len(p)-1] // remove terminating null - } - val = make([]string, 0, 5) - from := 0 - for i, c := range p { - if c == 0 { - val = append(val, syscall.UTF16ToString(p[from:i])) - from = i + 1 - } - } - return val, typ, nil -} - -// GetIntegerValue retrieves the integer value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetIntegerValue returns ErrNotExist. -// If value is not DWORD or QWORD, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 8)) - if err2 != nil { - return 0, typ, err2 - } - switch typ { - case DWORD: - if len(data) != 4 { - return 0, typ, errors.New("DWORD value is not 4 bytes long") - } - return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil - case QWORD: - if len(data) != 8 { - return 0, typ, errors.New("QWORD value is not 8 bytes long") - } - return *(*uint64)(unsafe.Pointer(&data[0])), QWORD, nil - default: - return 0, typ, ErrUnexpectedType - } -} - -// GetBinaryValue retrieves the binary value for the specified -// value name associated with an open key k. It also returns the value's type. -// If value does not exist, GetBinaryValue returns ErrNotExist. -// If value is not BINARY, it will return the correct value -// type and ErrUnexpectedType. -func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { - data, typ, err2 := k.getValue(name, make([]byte, 64)) - if err2 != nil { - return nil, typ, err2 - } - if typ != BINARY { - return nil, typ, ErrUnexpectedType - } - return data, typ, nil -} - -func (k Key) setValue(name string, valtype uint32, data []byte) error { - p, err := syscall.UTF16PtrFromString(name) - if err != nil { - return err - } - if len(data) == 0 { - return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) - } - return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) -} - -// SetDWordValue sets the data and type of a name value -// under key k to value and DWORD. -func (k Key) SetDWordValue(name string, value uint32) error { - return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) -} - -// SetQWordValue sets the data and type of a name value -// under key k to value and QWORD. -func (k Key) SetQWordValue(name string, value uint64) error { - return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) -} - -func (k Key) setStringValue(name string, valtype uint32, value string) error { - v, err := syscall.UTF16FromString(value) - if err != nil { - return err - } - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2] - return k.setValue(name, valtype, buf) -} - -// SetStringValue sets the data and type of a name value -// under key k to value and SZ. The value must not contain a zero byte. -func (k Key) SetStringValue(name, value string) error { - return k.setStringValue(name, SZ, value) -} - -// SetExpandStringValue sets the data and type of a name value -// under key k to value and EXPAND_SZ. The value must not contain a zero byte. -func (k Key) SetExpandStringValue(name, value string) error { - return k.setStringValue(name, EXPAND_SZ, value) -} - -// SetStringsValue sets the data and type of a name value -// under key k to value and MULTI_SZ. The value strings -// must not contain a zero byte. -func (k Key) SetStringsValue(name string, value []string) error { - ss := "" - for _, s := range value { - for i := 0; i < len(s); i++ { - if s[i] == 0 { - return errors.New("string cannot have 0 inside") - } - } - ss += s + "\x00" - } - v := utf16.Encode([]rune(ss + "\x00")) - buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[: len(v)*2 : len(v)*2] - return k.setValue(name, MULTI_SZ, buf) -} - -// SetBinaryValue sets the data and type of a name value -// under key k to value and BINARY. -func (k Key) SetBinaryValue(name string, value []byte) error { - return k.setValue(name, BINARY, value) -} - -// DeleteValue removes a named value from the key k. -func (k Key) DeleteValue(name string) error { - return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) -} - -// ReadValueNames returns the value names of key k. -func (k Key) ReadValueNames() ([]string, error) { - ki, err := k.Stat() - if err != nil { - return nil, err - } - names := make([]string, 0, ki.ValueCount) - buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character -loopItems: - for i := uint32(0); ; i++ { - l := uint32(len(buf)) - for { - err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) - if err == nil { - break - } - if err == syscall.ERROR_MORE_DATA { - // Double buffer size and try again. - l = uint32(2 * len(buf)) - buf = make([]uint16, l) - continue - } - if err == _ERROR_NO_MORE_ITEMS { - break loopItems - } - return names, err - } - names = append(names, syscall.UTF16ToString(buf[:l])) - } - return names, nil -} diff --git a/testing/internal/syscall/windows/registry/zsyscall_windows.go b/testing/internal/syscall/windows/registry/zsyscall_windows.go deleted file mode 100644 index 4cf674c2..00000000 --- a/testing/internal/syscall/windows/registry/zsyscall_windows.go +++ /dev/null @@ -1,107 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package registry - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows/sysdll" - "syscall" - "unsafe" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = syscall.EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) - modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) - - procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW") - procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW") - procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW") - procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") - procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW") - procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW") - procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") -) - -func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition))) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) { - r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) { - r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize)) - if r0 != 0 { - regerrno = syscall.Errno(r0) - } - return -} - -func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} diff --git a/testing/internal/syscall/windows/reparse_windows.go b/testing/internal/syscall/windows/reparse_windows.go deleted file mode 100644 index 241dd523..00000000 --- a/testing/internal/syscall/windows/reparse_windows.go +++ /dev/null @@ -1,94 +0,0 @@ -// 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 windows - -import ( - "syscall" - "unsafe" -) - -// Reparse tag values are taken from -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4 -const ( - FSCTL_SET_REPARSE_POINT = 0x000900A4 - IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 - IO_REPARSE_TAG_DEDUP = 0x80000013 - IO_REPARSE_TAG_AF_UNIX = 0x80000023 - - SYMLINK_FLAG_RELATIVE = 1 -) - -// These structures are described -// in https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ca069dad-ed16-42aa-b057-b6b207f447cc -// and https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913. - -type REPARSE_DATA_BUFFER struct { - ReparseTag uint32 - ReparseDataLength uint16 - Reserved uint16 - DUMMYUNIONNAME byte -} - -// REPARSE_DATA_BUFFER_HEADER is a common part of REPARSE_DATA_BUFFER structure. -type REPARSE_DATA_BUFFER_HEADER struct { - ReparseTag uint32 - // The size, in bytes, of the reparse data that follows - // the common portion of the REPARSE_DATA_BUFFER element. - // This value is the length of the data starting at the - // SubstituteNameOffset field. - ReparseDataLength uint16 - Reserved uint16 -} - -type SymbolicLinkReparseBuffer struct { - // The integer that contains the offset, in bytes, - // of the substitute name string in the PathBuffer array, - // computed as an offset from byte 0 of PathBuffer. Note that - // this offset must be divided by 2 to get the array index. - SubstituteNameOffset uint16 - // The integer that contains the length, in bytes, of the - // substitute name string. If this string is null-terminated, - // SubstituteNameLength does not include the Unicode null character. - SubstituteNameLength uint16 - // PrintNameOffset is similar to SubstituteNameOffset. - PrintNameOffset uint16 - // PrintNameLength is similar to SubstituteNameLength. - PrintNameLength uint16 - // Flags specifies whether the substitute name is a full path name or - // a path name relative to the directory containing the symbolic link. - Flags uint32 - PathBuffer [1]uint16 -} - -// Path returns path stored in rb. -func (rb *SymbolicLinkReparseBuffer) Path() string { - n1 := rb.SubstituteNameOffset / 2 - n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2 - return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2]) -} - -type MountPointReparseBuffer struct { - // The integer that contains the offset, in bytes, - // of the substitute name string in the PathBuffer array, - // computed as an offset from byte 0 of PathBuffer. Note that - // this offset must be divided by 2 to get the array index. - SubstituteNameOffset uint16 - // The integer that contains the length, in bytes, of the - // substitute name string. If this string is null-terminated, - // SubstituteNameLength does not include the Unicode null character. - SubstituteNameLength uint16 - // PrintNameOffset is similar to SubstituteNameOffset. - PrintNameOffset uint16 - // PrintNameLength is similar to SubstituteNameLength. - PrintNameLength uint16 - PathBuffer [1]uint16 -} - -// Path returns path stored in rb. -func (rb *MountPointReparseBuffer) Path() string { - n1 := rb.SubstituteNameOffset / 2 - n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2 - return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2]) -} diff --git a/testing/internal/syscall/windows/security_windows.go b/testing/internal/syscall/windows/security_windows.go deleted file mode 100644 index f0ab52ac..00000000 --- a/testing/internal/syscall/windows/security_windows.go +++ /dev/null @@ -1,264 +0,0 @@ -// 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 windows - -import ( - "runtime" - "syscall" - "unsafe" -) - -const ( - SecurityAnonymous = 0 - SecurityIdentification = 1 - SecurityImpersonation = 2 - SecurityDelegation = 3 -) - -//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf -//sys RevertToSelf() (err error) = advapi32.RevertToSelf -//sys ImpersonateLoggedOnUser(token syscall.Token) (err error) = advapi32.ImpersonateLoggedOnUser -//sys LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *syscall.Token) (err error) = advapi32.LogonUserW - -const ( - TOKEN_ADJUST_PRIVILEGES = 0x0020 - SE_PRIVILEGE_ENABLED = 0x00000002 -) - -type LUID struct { - LowPart uint32 - HighPart int32 -} - -type LUID_AND_ATTRIBUTES struct { - Luid LUID - Attributes uint32 -} - -type TOKEN_PRIVILEGES struct { - PrivilegeCount uint32 - Privileges [1]LUID_AND_ATTRIBUTES -} - -//sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken -//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW -//sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges - -func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error { - ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen) - if ret == 0 { - // AdjustTokenPrivileges call failed - return err - } - // AdjustTokenPrivileges call succeeded - if err == syscall.EINVAL { - // GetLastError returned ERROR_SUCCESS - return nil - } - return err -} - -//sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx -//sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation - -type SID_AND_ATTRIBUTES struct { - Sid *syscall.SID - Attributes uint32 -} - -type TOKEN_MANDATORY_LABEL struct { - Label SID_AND_ATTRIBUTES -} - -func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 { - return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid) -} - -const SE_GROUP_INTEGRITY = 0x00000020 - -type TokenType uint32 - -const ( - TokenPrimary TokenType = 1 - TokenImpersonation TokenType = 2 -) - -//sys GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) = userenv.GetProfilesDirectoryW - -const ( - LG_INCLUDE_INDIRECT = 0x1 - MAX_PREFERRED_LENGTH = 0xFFFFFFFF -) - -type LocalGroupUserInfo0 struct { - Name *uint16 -} - -const ( - NERR_UserNotFound syscall.Errno = 2221 - NERR_UserExists syscall.Errno = 2224 -) - -const ( - USER_PRIV_USER = 1 -) - -type UserInfo1 struct { - Name *uint16 - Password *uint16 - PasswordAge uint32 - Priv uint32 - HomeDir *uint16 - Comment *uint16 - Flags uint32 - ScriptPath *uint16 -} - -type UserInfo4 struct { - Name *uint16 - Password *uint16 - PasswordAge uint32 - Priv uint32 - HomeDir *uint16 - Comment *uint16 - Flags uint32 - ScriptPath *uint16 - AuthFlags uint32 - FullName *uint16 - UsrComment *uint16 - Parms *uint16 - Workstations *uint16 - LastLogon uint32 - LastLogoff uint32 - AcctExpires uint32 - MaxStorage uint32 - UnitsPerWeek uint32 - LogonHours *byte - BadPwCount uint32 - NumLogons uint32 - LogonServer *uint16 - CountryCode uint32 - CodePage uint32 - UserSid *syscall.SID - PrimaryGroupID uint32 - Profile *uint16 - HomeDirDrive *uint16 - PasswordExpired uint32 -} - -//sys NetUserAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint32) (neterr error) = netapi32.NetUserAdd -//sys NetUserDel(serverName *uint16, userName *uint16) (neterr error) = netapi32.NetUserDel -//sys NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) = netapi32.NetUserGetLocalGroups - -// GetSystemDirectory retrieves the path to current location of the system -// directory, which is typically, though not always, `C:\Windows\System32`. -// -//go:linkname GetSystemDirectory -func GetSystemDirectory() string // Implemented in runtime package. - -// GetUserName retrieves the user name of the current thread -// in the specified format. -func GetUserName(format uint32) (string, error) { - n := uint32(50) - for { - b := make([]uint16, n) - e := syscall.GetUserNameEx(format, &b[0], &n) - if e == nil { - return syscall.UTF16ToString(b[:n]), nil - } - if e != syscall.ERROR_MORE_DATA { - return "", e - } - if n <= uint32(len(b)) { - return "", e - } - } -} - -// getTokenInfo retrieves a specified type of information about an access token. -func getTokenInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) { - n := uint32(initSize) - for { - b := make([]byte, n) - e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n) - if e == nil { - return unsafe.Pointer(&b[0]), nil - } - if e != syscall.ERROR_INSUFFICIENT_BUFFER { - return nil, e - } - if n <= uint32(len(b)) { - return nil, e - } - } -} - -type TOKEN_GROUPS struct { - GroupCount uint32 - Groups [1]SID_AND_ATTRIBUTES -} - -func (g *TOKEN_GROUPS) AllGroups() []SID_AND_ATTRIBUTES { - return (*[(1 << 28) - 1]SID_AND_ATTRIBUTES)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount] -} - -func GetTokenGroups(t syscall.Token) (*TOKEN_GROUPS, error) { - i, e := getTokenInfo(t, syscall.TokenGroups, 50) - if e != nil { - return nil, e - } - return (*TOKEN_GROUPS)(i), nil -} - -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority -type SID_IDENTIFIER_AUTHORITY struct { - Value [6]byte -} - -const ( - SID_REVISION = 1 - // https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account - SECURITY_LOCAL_SYSTEM_RID = 18 - // https://learn.microsoft.com/en-us/windows/win32/services/localservice-account - SECURITY_LOCAL_SERVICE_RID = 19 - // https://learn.microsoft.com/en-us/windows/win32/services/networkservice-account - SECURITY_NETWORK_SERVICE_RID = 20 -) - -var SECURITY_NT_AUTHORITY = SID_IDENTIFIER_AUTHORITY{ - Value: [6]byte{0, 0, 0, 0, 0, 5}, -} - -//sys IsValidSid(sid *syscall.SID) (valid bool) = advapi32.IsValidSid -//sys getSidIdentifierAuthority(sid *syscall.SID) (idauth uintptr) = advapi32.GetSidIdentifierAuthority -//sys getSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) (subAuth uintptr) = advapi32.GetSidSubAuthority -//sys getSidSubAuthorityCount(sid *syscall.SID) (count uintptr) = advapi32.GetSidSubAuthorityCount - -// The following GetSid* functions are marked as //go:nocheckptr because checkptr -// instrumentation can't see that the pointer returned by the syscall is pointing -// into the sid's memory, which is normally allocated on the Go heap. Therefore, -// the checkptr instrumentation would incorrectly flag the pointer dereference -// as pointing to an invalid allocation. -// Also, use runtime.KeepAlive to ensure that the sid is not garbage collected -// before the GetSid* functions return, as the Go GC is not aware that the -// pointers returned by the syscall are pointing into the sid's memory. - -//go:nocheckptr -func GetSidIdentifierAuthority(sid *syscall.SID) SID_IDENTIFIER_AUTHORITY { - defer runtime.KeepAlive(sid) - return *(*SID_IDENTIFIER_AUTHORITY)(unsafe.Pointer(getSidIdentifierAuthority(sid))) -} - -//go:nocheckptr -func GetSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) uint32 { - defer runtime.KeepAlive(sid) - return *(*uint32)(unsafe.Pointer(getSidSubAuthority(sid, subAuthorityIdx))) -} - -//go:nocheckptr -func GetSidSubAuthorityCount(sid *syscall.SID) uint8 { - defer runtime.KeepAlive(sid) - return *(*uint8)(unsafe.Pointer(getSidSubAuthorityCount(sid))) -} diff --git a/testing/internal/syscall/windows/string_windows.go b/testing/internal/syscall/windows/string_windows.go deleted file mode 100644 index eb6893d7..00000000 --- a/testing/internal/syscall/windows/string_windows.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2024 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 windows - -import "syscall" - -// NTUnicodeString is a UTF-16 string for NT native APIs, corresponding to UNICODE_STRING. -type NTUnicodeString struct { - Length uint16 - MaximumLength uint16 - Buffer *uint16 -} - -// NewNTUnicodeString returns a new NTUnicodeString structure for use with native -// NT APIs that work over the NTUnicodeString type. Note that most Windows APIs -// do not use NTUnicodeString, and instead UTF16PtrFromString should be used for -// the more common *uint16 string type. -func NewNTUnicodeString(s string) (*NTUnicodeString, error) { - s16, err := syscall.UTF16FromString(s) - if err != nil { - return nil, err - } - n := uint16(len(s16) * 2) - // https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdmsec/nf-wdmsec-wdmlibrtlinitunicodestringex - return &NTUnicodeString{ - Length: n - 2, // subtract 2 bytes for the NUL terminator - MaximumLength: n, - Buffer: &s16[0], - }, nil -} diff --git a/testing/internal/syscall/windows/symlink_windows.go b/testing/internal/syscall/windows/symlink_windows.go deleted file mode 100644 index b8249b38..00000000 --- a/testing/internal/syscall/windows/symlink_windows.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 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 windows - -import "syscall" - -const ( - ERROR_INVALID_PARAMETER syscall.Errno = 87 - - FILE_SUPPORTS_OBJECT_IDS = 0x00010000 - FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 - - // symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972) - SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2 - - // FileInformationClass values - FileBasicInfo = 0 // FILE_BASIC_INFO - FileStandardInfo = 1 // FILE_STANDARD_INFO - FileNameInfo = 2 // FILE_NAME_INFO - FileDispositionInfo = 4 // FILE_DISPOSITION_INFO - FileStreamInfo = 7 // FILE_STREAM_INFO - FileCompressionInfo = 8 // FILE_COMPRESSION_INFO - FileAttributeTagInfo = 9 // FILE_ATTRIBUTE_TAG_INFO - FileIdBothDirectoryInfo = 0xa // FILE_ID_BOTH_DIR_INFO - FileIdBothDirectoryRestartInfo = 0xb // FILE_ID_BOTH_DIR_INFO - FileRemoteProtocolInfo = 0xd // FILE_REMOTE_PROTOCOL_INFO - FileFullDirectoryInfo = 0xe // FILE_FULL_DIR_INFO - FileFullDirectoryRestartInfo = 0xf // FILE_FULL_DIR_INFO - FileStorageInfo = 0x10 // FILE_STORAGE_INFO - FileAlignmentInfo = 0x11 // FILE_ALIGNMENT_INFO - FileIdInfo = 0x12 // FILE_ID_INFO - FileIdExtdDirectoryInfo = 0x13 // FILE_ID_EXTD_DIR_INFO - FileIdExtdDirectoryRestartInfo = 0x14 // FILE_ID_EXTD_DIR_INFO -) - -type FILE_ATTRIBUTE_TAG_INFO struct { - FileAttributes uint32 - ReparseTag uint32 -} - -//sys GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error) diff --git a/testing/internal/syscall/windows/syscall_windows.go b/testing/internal/syscall/windows/syscall_windows.go deleted file mode 100644 index c34cc795..00000000 --- a/testing/internal/syscall/windows/syscall_windows.go +++ /dev/null @@ -1,579 +0,0 @@ -// Copyright 2014 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 windows - -import ( - "sync" - "syscall" - "unsafe" -) - -// CanUseLongPaths is true when the OS supports opting into -// proper long path handling without the need for fixups. -// -//go:linkname CanUseLongPaths -var CanUseLongPaths bool - -// UTF16PtrToString is like UTF16ToString, but takes *uint16 -// as a parameter instead of []uint16. -func UTF16PtrToString(p *uint16) string { - if p == nil { - return "" - } - end := unsafe.Pointer(p) - n := 0 - for *(*uint16)(end) != 0 { - end = unsafe.Pointer(uintptr(end) + unsafe.Sizeof(*p)) - n++ - } - return syscall.UTF16ToString(unsafe.Slice(p, n)) -} - -const ( - ERROR_INVALID_HANDLE syscall.Errno = 6 - ERROR_BAD_LENGTH syscall.Errno = 24 - ERROR_SHARING_VIOLATION syscall.Errno = 32 - ERROR_LOCK_VIOLATION syscall.Errno = 33 - ERROR_NOT_SUPPORTED syscall.Errno = 50 - ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120 - ERROR_INVALID_NAME syscall.Errno = 123 - ERROR_LOCK_FAILED syscall.Errno = 167 - ERROR_IO_INCOMPLETE syscall.Errno = 996 - ERROR_NO_TOKEN syscall.Errno = 1008 - ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113 - ERROR_CANT_ACCESS_FILE syscall.Errno = 1920 -) - -const ( - GAA_FLAG_INCLUDE_PREFIX = 0x00000010 - GAA_FLAG_INCLUDE_GATEWAYS = 0x0080 -) - -const ( - IF_TYPE_OTHER = 1 - IF_TYPE_ETHERNET_CSMACD = 6 - IF_TYPE_ISO88025_TOKENRING = 9 - IF_TYPE_PPP = 23 - IF_TYPE_SOFTWARE_LOOPBACK = 24 - IF_TYPE_ATM = 37 - IF_TYPE_IEEE80211 = 71 - IF_TYPE_TUNNEL = 131 - IF_TYPE_IEEE1394 = 144 -) - -type SocketAddress struct { - Sockaddr *syscall.RawSockaddrAny - SockaddrLength int32 -} - -type IpAdapterUnicastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterUnicastAddress - Address SocketAddress - PrefixOrigin int32 - SuffixOrigin int32 - DadState int32 - ValidLifetime uint32 - PreferredLifetime uint32 - LeaseLifetime uint32 - OnLinkPrefixLength uint8 -} - -type IpAdapterAnycastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterAnycastAddress - Address SocketAddress -} - -type IpAdapterMulticastAddress struct { - Length uint32 - Flags uint32 - Next *IpAdapterMulticastAddress - Address SocketAddress -} - -type IpAdapterDnsServerAdapter struct { - Length uint32 - Reserved uint32 - Next *IpAdapterDnsServerAdapter - Address SocketAddress -} - -type IpAdapterPrefix struct { - Length uint32 - Flags uint32 - Next *IpAdapterPrefix - Address SocketAddress - PrefixLength uint32 -} - -type IpAdapterWinsServerAddress struct { - Length uint32 - Reserved uint32 - Next *IpAdapterWinsServerAddress - Address SocketAddress -} - -type IpAdapterGatewayAddress struct { - Length uint32 - Reserved uint32 - Next *IpAdapterGatewayAddress - Address SocketAddress -} - -type IpAdapterAddresses struct { - Length uint32 - IfIndex uint32 - Next *IpAdapterAddresses - AdapterName *byte - FirstUnicastAddress *IpAdapterUnicastAddress - FirstAnycastAddress *IpAdapterAnycastAddress - FirstMulticastAddress *IpAdapterMulticastAddress - FirstDnsServerAddress *IpAdapterDnsServerAdapter - DnsSuffix *uint16 - Description *uint16 - FriendlyName *uint16 - PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte - PhysicalAddressLength uint32 - Flags uint32 - Mtu uint32 - IfType uint32 - OperStatus uint32 - Ipv6IfIndex uint32 - ZoneIndices [16]uint32 - FirstPrefix *IpAdapterPrefix - TransmitLinkSpeed uint64 - ReceiveLinkSpeed uint64 - FirstWinsServerAddress *IpAdapterWinsServerAddress - FirstGatewayAddress *IpAdapterGatewayAddress - /* more fields might be present here. */ -} - -type SecurityAttributes struct { - Length uint16 - SecurityDescriptor uintptr - InheritHandle bool -} - -type FILE_BASIC_INFO struct { - CreationTime int64 - LastAccessTime int64 - LastWriteTime int64 - ChangedTime int64 - FileAttributes uint32 - - // Pad out to 8-byte alignment. - // - // Without this padding, TestChmod fails due to an argument validation error - // in SetFileInformationByHandle on windows/386. - // - // https://learn.microsoft.com/en-us/cpp/build/reference/zp-struct-member-alignment?view=msvc-170 - // says that “The C/C++ headers in the Windows SDK assume the platform's - // default alignment is used.” What we see here is padding rather than - // alignment, but maybe it is related. - _ uint32 -} - -const ( - IfOperStatusUp = 1 - IfOperStatusDown = 2 - IfOperStatusTesting = 3 - IfOperStatusUnknown = 4 - IfOperStatusDormant = 5 - IfOperStatusNotPresent = 6 - IfOperStatusLowerLayerDown = 7 -) - -//sys GetAdaptersAddresses(family uint32, flags uint32, reserved unsafe.Pointer, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses -//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW -//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW -//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW -//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle -//sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery -//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W - -const ( - // flags for CreateToolhelp32Snapshot - TH32CS_SNAPMODULE = 0x08 - TH32CS_SNAPMODULE32 = 0x10 -) - -const MAX_MODULE_NAME32 = 255 - -type ModuleEntry32 struct { - Size uint32 - ModuleID uint32 - ProcessID uint32 - GlblcntUsage uint32 - ProccntUsage uint32 - ModBaseAddr uintptr - ModBaseSize uint32 - ModuleHandle syscall.Handle - Module [MAX_MODULE_NAME32 + 1]uint16 - ExePath [syscall.MAX_PATH]uint16 -} - -const SizeofModuleEntry32 = unsafe.Sizeof(ModuleEntry32{}) - -//sys Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW -//sys Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW - -const ( - WSA_FLAG_OVERLAPPED = 0x01 - WSA_FLAG_NO_HANDLE_INHERIT = 0x80 - - WSAEINVAL syscall.Errno = 10022 - WSAEMSGSIZE syscall.Errno = 10040 - WSAEAFNOSUPPORT syscall.Errno = 10047 - - MSG_PEEK = 0x2 - MSG_TRUNC = 0x0100 - MSG_CTRUNC = 0x0200 - - socket_error = uintptr(^uint32(0)) -) - -var WSAID_WSASENDMSG = syscall.GUID{ - Data1: 0xa441e712, - Data2: 0x754f, - Data3: 0x43ca, - Data4: [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d}, -} - -var WSAID_WSARECVMSG = syscall.GUID{ - Data1: 0xf689d7c8, - Data2: 0x6f1f, - Data3: 0x436b, - Data4: [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22}, -} - -var sendRecvMsgFunc struct { - once sync.Once - sendAddr uintptr - recvAddr uintptr - err error -} - -type WSAMsg struct { - Name syscall.Pointer - Namelen int32 - Buffers *syscall.WSABuf - BufferCount uint32 - Control syscall.WSABuf - Flags uint32 -} - -//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW -//sys WSADuplicateSocket(s syscall.Handle, processID uint32, info *syscall.WSAProtocolInfo) (err error) [failretval!=0] = ws2_32.WSADuplicateSocketW -//sys WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult - -func loadWSASendRecvMsg() error { - sendRecvMsgFunc.once.Do(func() { - var s syscall.Handle - s, sendRecvMsgFunc.err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) - if sendRecvMsgFunc.err != nil { - return - } - defer syscall.CloseHandle(s) - var n uint32 - sendRecvMsgFunc.err = syscall.WSAIoctl(s, - syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)), - uint32(unsafe.Sizeof(WSAID_WSARECVMSG)), - (*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)), - uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)), - &n, nil, 0) - if sendRecvMsgFunc.err != nil { - return - } - sendRecvMsgFunc.err = syscall.WSAIoctl(s, - syscall.SIO_GET_EXTENSION_FUNCTION_POINTER, - (*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)), - uint32(unsafe.Sizeof(WSAID_WSASENDMSG)), - (*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)), - uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)), - &n, nil, 0) - }) - return sendRecvMsgFunc.err -} - -func WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, croutine *byte) error { - err := loadWSASendRecvMsg() - if err != nil { - return err - } - r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.sendAddr, 6, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine))) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return err -} - -func WSARecvMsg(fd syscall.Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *syscall.Overlapped, croutine *byte) error { - err := loadWSASendRecvMsg() - if err != nil { - return err - } - r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.recvAddr, 5, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0) - if r1 == socket_error { - if e1 != 0 { - err = errnoErr(e1) - } else { - err = syscall.EINVAL - } - } - return err -} - -const ( - ComputerNameNetBIOS = 0 - ComputerNameDnsHostname = 1 - ComputerNameDnsDomain = 2 - ComputerNameDnsFullyQualified = 3 - ComputerNamePhysicalNetBIOS = 4 - ComputerNamePhysicalDnsHostname = 5 - ComputerNamePhysicalDnsDomain = 6 - ComputerNamePhysicalDnsFullyQualified = 7 - ComputerNameMax = 8 - - MOVEFILE_REPLACE_EXISTING = 0x1 - MOVEFILE_COPY_ALLOWED = 0x2 - MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 - MOVEFILE_WRITE_THROUGH = 0x8 - MOVEFILE_CREATE_HARDLINK = 0x10 - MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 -) - -func Rename(oldpath, newpath string) error { - from, err := syscall.UTF16PtrFromString(oldpath) - if err != nil { - return err - } - to, err := syscall.UTF16PtrFromString(newpath) - if err != nil { - return err - } - return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) -} - -//sys LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.LockFileEx -//sys UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.UnlockFileEx - -const ( - LOCKFILE_FAIL_IMMEDIATELY = 0x00000001 - LOCKFILE_EXCLUSIVE_LOCK = 0x00000002 -) - -const MB_ERR_INVALID_CHARS = 8 - -//sys GetACP() (acp uint32) = kernel32.GetACP -//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP -//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar -//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread - -// Constants from lmshare.h -const ( - STYPE_DISKTREE = 0x00 - STYPE_TEMPORARY = 0x40000000 -) - -type SHARE_INFO_2 struct { - Netname *uint16 - Type uint32 - Remark *uint16 - Permissions uint32 - MaxUses uint32 - CurrentUses uint32 - Path *uint16 - Passwd *uint16 -} - -//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd -//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel - -const ( - FILE_NAME_NORMALIZED = 0x0 - FILE_NAME_OPENED = 0x8 - - VOLUME_NAME_DOS = 0x0 - VOLUME_NAME_GUID = 0x1 - VOLUME_NAME_NONE = 0x4 - VOLUME_NAME_NT = 0x2 -) - -//sys GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW - -func ErrorLoadingGetTempPath2() error { - return procGetTempPath2W.Find() -} - -//sys CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock -//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock -//sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW - -//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng - -type FILE_ID_BOTH_DIR_INFO struct { - NextEntryOffset uint32 - FileIndex uint32 - CreationTime syscall.Filetime - LastAccessTime syscall.Filetime - LastWriteTime syscall.Filetime - ChangeTime syscall.Filetime - EndOfFile uint64 - AllocationSize uint64 - FileAttributes uint32 - FileNameLength uint32 - EaSize uint32 - ShortNameLength uint32 - ShortName [12]uint16 - FileID uint64 - FileName [1]uint16 -} - -type FILE_FULL_DIR_INFO struct { - NextEntryOffset uint32 - FileIndex uint32 - CreationTime syscall.Filetime - LastAccessTime syscall.Filetime - LastWriteTime syscall.Filetime - ChangeTime syscall.Filetime - EndOfFile uint64 - AllocationSize uint64 - FileAttributes uint32 - FileNameLength uint32 - EaSize uint32 - FileName [1]uint16 -} - -//sys GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) = GetVolumeInformationByHandleW -//sys GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) = GetVolumeNameForVolumeMountPointW - -type RUNTIME_FUNCTION struct { - BeginAddress uint32 - EndAddress uint32 - UnwindData uint32 -} - -//sys RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table unsafe.Pointer) (ret *RUNTIME_FUNCTION) = kernel32.RtlLookupFunctionEntry -//sys RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry *RUNTIME_FUNCTION, ctxt unsafe.Pointer, data unsafe.Pointer, frame *uintptr, ctxptrs unsafe.Pointer) (ret uintptr) = kernel32.RtlVirtualUnwind - -type SERVICE_STATUS struct { - ServiceType uint32 - CurrentState uint32 - ControlsAccepted uint32 - Win32ExitCode uint32 - ServiceSpecificExitCode uint32 - CheckPoint uint32 - WaitHint uint32 -} - -const ( - SERVICE_RUNNING = 4 - SERVICE_QUERY_STATUS = 4 -) - -//sys OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) = advapi32.OpenServiceW -//sys QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus -//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) [failretval==0] = advapi32.OpenSCManagerW - -func FinalPath(h syscall.Handle, flags uint32) (string, error) { - buf := make([]uint16, 100) - for { - n, err := GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), flags) - if err != nil { - return "", err - } - if n < uint32(len(buf)) { - break - } - buf = make([]uint16, n) - } - return syscall.UTF16ToString(buf), nil -} - -// QueryPerformanceCounter retrieves the current value of performance counter. -// -//go:linkname QueryPerformanceCounter -func QueryPerformanceCounter() int64 // Implemented in runtime package. - -// QueryPerformanceFrequency retrieves the frequency of the performance counter. -// The returned value is represented as counts per second. -// -//go:linkname QueryPerformanceFrequency -func QueryPerformanceFrequency() int64 // Implemented in runtime package. - -//sys GetModuleHandle(modulename *uint16) (handle syscall.Handle, err error) = kernel32.GetModuleHandleW - -const ( - PIPE_ACCESS_INBOUND = 0x00000001 - PIPE_ACCESS_OUTBOUND = 0x00000002 - PIPE_ACCESS_DUPLEX = 0x00000003 - - PIPE_TYPE_BYTE = 0x00000000 - PIPE_TYPE_MESSAGE = 0x00000004 - - PIPE_READMODE_BYTE = 0x00000000 - PIPE_READMODE_MESSAGE = 0x00000002 -) - -//sys CreateIoCompletionPort(filehandle syscall.Handle, cphandle syscall.Handle, key uintptr, threadcnt uint32) (handle syscall.Handle, err error) -//sys GetOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, done *uint32, wait bool) (err error) -//sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW - -//sys ReOpenFile(filehandle syscall.Handle, desiredAccess uint32, shareMode uint32, flagAndAttributes uint32) (handle syscall.Handle, err error) - -// NTStatus corresponds with NTSTATUS, error values returned by ntdll.dll and -// other native functions. -type NTStatus uint32 - -func (s NTStatus) Errno() syscall.Errno { - return rtlNtStatusToDosErrorNoTeb(s) -} - -func langID(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) } - -func (s NTStatus) Error() string { - return s.Errno().Error() -} - -// x/sys/windows/mkerrors.bash can generate a complete list of NTStatus codes. -// -// At the moment, we only need a couple, so just put them here manually. -// If this list starts getting long, we should consider generating the full set. -const ( - STATUS_OBJECT_NAME_COLLISION NTStatus = 0xC0000035 - STATUS_FILE_IS_A_DIRECTORY NTStatus = 0xC00000BA - STATUS_DIRECTORY_NOT_EMPTY NTStatus = 0xC0000101 - STATUS_NOT_A_DIRECTORY NTStatus = 0xC0000103 - STATUS_CANNOT_DELETE NTStatus = 0xC0000121 - STATUS_REPARSE_POINT_ENCOUNTERED NTStatus = 0xC000050B - STATUS_NOT_SUPPORTED NTStatus = 0xC00000BB - STATUS_INVALID_PARAMETER NTStatus = 0xC000000D - STATUS_INVALID_INFO_CLASS NTStatus = 0xC0000003 -) - -const ( - FileModeInformation = 16 -) - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_mode_information -type FILE_MODE_INFORMATION struct { - Mode uint32 -} - -// NT Native APIs -//sys NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer unsafe.Pointer, ealength uint32) (ntstatus error) = ntdll.NtCreateFile -//sys NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) = ntdll.NtOpenFile -//sys rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosErrorNoTeb -//sys NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer unsafe.Pointer, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtSetInformationFile -//sys RtlIsDosDeviceName_U(name *uint16) (ret uint32) = ntdll.RtlIsDosDeviceName_U -//sys NtQueryInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer unsafe.Pointer, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtQueryInformationFile diff --git a/testing/internal/syscall/windows/sysdll/sysdll.go b/testing/internal/syscall/windows/sysdll/sysdll.go deleted file mode 100644 index e79fd19e..00000000 --- a/testing/internal/syscall/windows/sysdll/sysdll.go +++ /dev/null @@ -1,30 +0,0 @@ -// 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. - -//go:build windows - -// Package sysdll is an internal leaf package that records and reports -// which Windows DLL names are used by Go itself. These DLLs are then -// only loaded from the System32 directory. See Issue 14959. -package sysdll - -// IsSystemDLL reports whether the named dll key (a base name, like -// "foo.dll") is a system DLL which should only be loaded from the -// Windows SYSTEM32 directory. -// -// Filenames are case sensitive, but that doesn't matter because -// the case registered with Add is also the same case used with -// LoadDLL later. -// -// It has no associated mutex and should only be mutated serially -// (currently: during init), and not concurrent with DLL loading. -var IsSystemDLL = map[string]bool{} - -// Add notes that dll is a system32 DLL which should only be loaded -// from the Windows SYSTEM32 directory. It returns its argument back, -// for ease of use in generated code. -func Add(dll string) string { - IsSystemDLL[dll] = true - return dll -} diff --git a/testing/internal/syscall/windows/types_windows.go b/testing/internal/syscall/windows/types_windows.go deleted file mode 100644 index 6d989e7e..00000000 --- a/testing/internal/syscall/windows/types_windows.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2024 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 windows - -import ( - "syscall" - "unsafe" -) - -// Socket related. -const ( - TCP_KEEPIDLE = 0x03 - TCP_KEEPCNT = 0x10 - TCP_KEEPINTVL = 0x11 - - SIO_UDP_NETRESET = syscall.IOC_IN | syscall.IOC_VENDOR | 15 -) - -const ( - FILE_READ_DATA = 0x00000001 - FILE_READ_ATTRIBUTES = 0x00000080 - FILE_READ_EA = 0x00000008 - FILE_WRITE_DATA = 0x00000002 - FILE_WRITE_ATTRIBUTES = 0x00000100 - FILE_WRITE_EA = 0x00000010 - FILE_APPEND_DATA = 0x00000004 - FILE_EXECUTE = 0x00000020 - - FILE_GENERIC_READ = STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE - FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE - FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE - - FILE_LIST_DIRECTORY = 0x00000001 - FILE_TRAVERSE = 0x00000020 - - FILE_SHARE_READ = 0x00000001 - FILE_SHARE_WRITE = 0x00000002 - FILE_SHARE_DELETE = 0x00000004 - FILE_ATTRIBUTE_READONLY = 0x00000001 - FILE_ATTRIBUTE_HIDDEN = 0x00000002 - FILE_ATTRIBUTE_SYSTEM = 0x00000004 - FILE_ATTRIBUTE_DIRECTORY = 0x00000010 - FILE_ATTRIBUTE_ARCHIVE = 0x00000020 - FILE_ATTRIBUTE_DEVICE = 0x00000040 - FILE_ATTRIBUTE_NORMAL = 0x00000080 - FILE_ATTRIBUTE_TEMPORARY = 0x00000100 - FILE_ATTRIBUTE_SPARSE_FILE = 0x00000200 - FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400 - FILE_ATTRIBUTE_COMPRESSED = 0x00000800 - FILE_ATTRIBUTE_OFFLINE = 0x00001000 - FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000 - FILE_ATTRIBUTE_ENCRYPTED = 0x00004000 - FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x00008000 - FILE_ATTRIBUTE_VIRTUAL = 0x00010000 - FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x00020000 - FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x00040000 - FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x00400000 - - INVALID_FILE_ATTRIBUTES = 0xffffffff -) - -// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask -type ACCESS_MASK uint32 - -// Constants for type ACCESS_MASK -const ( - DELETE = 0x00010000 - READ_CONTROL = 0x00020000 - WRITE_DAC = 0x00040000 - WRITE_OWNER = 0x00080000 - SYNCHRONIZE = 0x00100000 - STANDARD_RIGHTS_REQUIRED = 0x000F0000 - STANDARD_RIGHTS_READ = READ_CONTROL - STANDARD_RIGHTS_WRITE = READ_CONTROL - STANDARD_RIGHTS_EXECUTE = READ_CONTROL - STANDARD_RIGHTS_ALL = 0x001F0000 - SPECIFIC_RIGHTS_ALL = 0x0000FFFF - ACCESS_SYSTEM_SECURITY = 0x01000000 - MAXIMUM_ALLOWED = 0x02000000 - GENERIC_READ = 0x80000000 - GENERIC_WRITE = 0x40000000 - GENERIC_EXECUTE = 0x20000000 - GENERIC_ALL = 0x10000000 -) - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_acl -type ACL struct { - AclRevision byte - Sbz1 byte - AclSize uint16 - AceCount uint16 - Sbz2 uint16 -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_status_block -type IO_STATUS_BLOCK struct { - Status NTStatus - Information uintptr -} - -// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes -type OBJECT_ATTRIBUTES struct { - Length uint32 - RootDirectory syscall.Handle - ObjectName *NTUnicodeString - Attributes uint32 - SecurityDescriptor *SECURITY_DESCRIPTOR - SecurityQoS *SECURITY_QUALITY_OF_SERVICE -} - -// init sets o's RootDirectory, ObjectName, and Length. -func (o *OBJECT_ATTRIBUTES) init(root syscall.Handle, name string) error { - if name == "." { - name = "" - } - objectName, err := NewNTUnicodeString(name) - if err != nil { - return err - } - o.ObjectName = objectName - if root != syscall.InvalidHandle { - o.RootDirectory = root - } - o.Length = uint32(unsafe.Sizeof(*o)) - return nil -} - -// Values for the Attributes member of OBJECT_ATTRIBUTES. -const ( - OBJ_INHERIT = 0x00000002 - OBJ_PERMANENT = 0x00000010 - OBJ_EXCLUSIVE = 0x00000020 - OBJ_CASE_INSENSITIVE = 0x00000040 - OBJ_OPENIF = 0x00000080 - OBJ_OPENLINK = 0x00000100 - OBJ_KERNEL_HANDLE = 0x00000200 - OBJ_FORCE_ACCESS_CHECK = 0x00000400 - OBJ_IGNORE_IMPERSONATED_DEVICEMAP = 0x00000800 - OBJ_DONT_REPARSE = 0x00001000 - OBJ_VALID_ATTRIBUTES = 0x00001FF2 -) - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_security_descriptor -type SECURITY_DESCRIPTOR struct { - revision byte - sbz1 byte - control SECURITY_DESCRIPTOR_CONTROL - owner *syscall.SID - group *syscall.SID - sacl *ACL - dacl *ACL -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/security-descriptor-control -type SECURITY_DESCRIPTOR_CONTROL uint16 - -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-security_quality_of_service -type SECURITY_QUALITY_OF_SERVICE struct { - Length uint32 - ImpersonationLevel uint32 // type SECURITY_IMPERSONATION_LEVEL - ContextTrackingMode byte // type SECURITY_CONTEXT_TRACKING_MODE - EffectiveOnly byte -} - -const ( - // CreateDisposition flags for NtCreateFile and NtCreateNamedPipeFile. - FILE_SUPERSEDE = 0x00000000 - FILE_OPEN = 0x00000001 - FILE_CREATE = 0x00000002 - FILE_OPEN_IF = 0x00000003 - FILE_OVERWRITE = 0x00000004 - FILE_OVERWRITE_IF = 0x00000005 - FILE_MAXIMUM_DISPOSITION = 0x00000005 - - // CreateOptions flags for NtCreateFile and NtCreateNamedPipeFile. - FILE_DIRECTORY_FILE = 0x00000001 - FILE_WRITE_THROUGH = 0x00000002 - FILE_SEQUENTIAL_ONLY = 0x00000004 - FILE_NO_INTERMEDIATE_BUFFERING = 0x00000008 - FILE_SYNCHRONOUS_IO_ALERT = 0x00000010 - FILE_SYNCHRONOUS_IO_NONALERT = 0x00000020 - FILE_NON_DIRECTORY_FILE = 0x00000040 - FILE_CREATE_TREE_CONNECTION = 0x00000080 - FILE_COMPLETE_IF_OPLOCKED = 0x00000100 - FILE_NO_EA_KNOWLEDGE = 0x00000200 - FILE_OPEN_REMOTE_INSTANCE = 0x00000400 - FILE_RANDOM_ACCESS = 0x00000800 - FILE_DELETE_ON_CLOSE = 0x00001000 - FILE_OPEN_BY_FILE_ID = 0x00002000 - FILE_OPEN_FOR_BACKUP_INTENT = 0x00004000 - FILE_NO_COMPRESSION = 0x00008000 - FILE_OPEN_REQUIRING_OPLOCK = 0x00010000 - FILE_DISALLOW_EXCLUSIVE = 0x00020000 - FILE_RESERVE_OPFILTER = 0x00100000 - FILE_OPEN_REPARSE_POINT = 0x00200000 - FILE_OPEN_NO_RECALL = 0x00400000 - FILE_OPEN_FOR_FREE_SPACE_QUERY = 0x00800000 -) - -// https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_disposition_info -type FILE_DISPOSITION_INFO struct { - DeleteFile bool -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information -type FILE_DISPOSITION_INFORMATION struct { - DeleteFile bool -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex -type FILE_DISPOSITION_INFORMATION_EX struct { - Flags uint32 -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex -const ( - FILE_DISPOSITION_DO_NOT_DELETE = 0x00000000 - FILE_DISPOSITION_DELETE = 0x00000001 - FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002 - FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK = 0x00000004 - FILE_DISPOSITION_ON_CLOSE = 0x00000008 - FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE = 0x00000010 -) - -// Flags for FILE_RENAME_INFORMATION_EX. -const ( - FILE_RENAME_REPLACE_IF_EXISTS = 0x00000001 - FILE_RENAME_POSIX_SEMANTICS = 0x00000002 -) - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information -type FILE_RENAME_INFORMATION struct { - ReplaceIfExists bool - RootDirectory syscall.Handle - FileNameLength uint32 - FileName [syscall.MAX_PATH]uint16 -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_rename_information -type FILE_RENAME_INFORMATION_EX struct { - Flags uint32 - RootDirectory syscall.Handle - FileNameLength uint32 - FileName [syscall.MAX_PATH]uint16 -} - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_link_information -type FILE_LINK_INFORMATION struct { - ReplaceIfExists bool - RootDirectory syscall.Handle - FileNameLength uint32 - FileName [syscall.MAX_PATH]uint16 -} - -const FileReplaceCompletionInformation = 61 - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/ns-ntifs-_file_completion_information -type FILE_COMPLETION_INFORMATION struct { - Port syscall.Handle - Key uintptr -} - -// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexa -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw -const VER_NT_WORKSTATION = 0x0000001 diff --git a/testing/internal/syscall/windows/version_windows.go b/testing/internal/syscall/windows/version_windows.go deleted file mode 100644 index 5edf7a01..00000000 --- a/testing/internal/syscall/windows/version_windows.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2024 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 windows - -import ( - "errors" - "sync" - "syscall" - "unsafe" -) - -// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw -type _OSVERSIONINFOEXW struct { - osVersionInfoSize uint32 - majorVersion uint32 - minorVersion uint32 - buildNumber uint32 - platformId uint32 - csdVersion [128]uint16 - servicePackMajor uint16 - servicePackMinor uint16 - suiteMask uint16 - productType byte - reserved byte -} - -// According to documentation, RtlGetVersion function always succeeds. -//sys rtlGetVersion(info *_OSVERSIONINFOEXW) = ntdll.RtlGetVersion - -// Retrieves version information of the current Windows OS -// from the RtlGetVersion API. -func getVersionInfo() *_OSVERSIONINFOEXW { - info := _OSVERSIONINFOEXW{} - info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) - rtlGetVersion(&info) - return &info -} - -// Version retrieves the major, minor, and build version numbers -// of the current Windows OS from the RtlGetVersion API. -func Version() (major, minor, build uint32) { - info := getVersionInfo() - return info.majorVersion, info.minorVersion, info.buildNumber -} - -// SupportUnlimitedTransmitFile indicates whether the current -// Windows version's TransmitFile function imposes any -// concurrent operation limits. -// Workstation and client versions of Windows limit the number -// of concurrent TransmitFile operations allowed on the system -// to a maximum of two. Please see: -// https://learn.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile -// https://golang.org/issue/73746 -var SupportUnlimitedTransmitFile = sync.OnceValue(func() bool { - info := getVersionInfo() - return info.productType != VER_NT_WORKSTATION -}) - -var ( - supportTCPKeepAliveIdle bool - supportTCPKeepAliveInterval bool - supportTCPKeepAliveCount bool -) - -var initTCPKeepAlive = sync.OnceFunc(func() { - s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT) - if err != nil { - // Fallback to checking the Windows version. - major, _, build := Version() - supportTCPKeepAliveIdle = major >= 10 && build >= 16299 - supportTCPKeepAliveInterval = major >= 10 && build >= 16299 - supportTCPKeepAliveCount = major >= 10 && build >= 15063 - return - } - defer syscall.Closesocket(s) - var optSupported = func(opt int) bool { - err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) - return !errors.Is(err, syscall.WSAENOPROTOOPT) - } - supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE) - supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL) - supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT) -}) - -// SupportTCPKeepAliveIdle indicates whether TCP_KEEPIDLE is supported. -// The minimal requirement is Windows 10.0.16299. -func SupportTCPKeepAliveIdle() bool { - initTCPKeepAlive() - return supportTCPKeepAliveIdle -} - -// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. -// The minimal requirement is Windows 10.0.16299. -func SupportTCPKeepAliveInterval() bool { - initTCPKeepAlive() - return supportTCPKeepAliveInterval -} - -// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. -// supports TCP_KEEPCNT. -// The minimal requirement is Windows 10.0.15063. -func SupportTCPKeepAliveCount() bool { - initTCPKeepAlive() - return supportTCPKeepAliveCount -} - -// SupportTCPInitialRTONoSYNRetransmissions indicates whether the current -// Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS. -// The minimal requirement is Windows 10.0.16299. -var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool { - major, _, build := Version() - return major >= 10 && build >= 16299 -}) - -// SupportUnixSocket indicates whether the current Windows version supports -// Unix Domain Sockets. -// The minimal requirement is Windows 10.0.17063. -var SupportUnixSocket = sync.OnceValue(func() bool { - var size uint32 - // First call to get the required buffer size in bytes. - // Ignore the error, it will always fail. - _, _ = syscall.WSAEnumProtocols(nil, nil, &size) - n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{})) - // Second call to get the actual protocols. - buf := make([]syscall.WSAProtocolInfo, n) - n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size) - if err != nil { - return false - } - for i := int32(0); i < n; i++ { - if buf[i].AddressFamily == syscall.AF_UNIX { - return true - } - } - return false -}) diff --git a/testing/internal/syscall/windows/version_windows_test.go b/testing/internal/syscall/windows/version_windows_test.go deleted file mode 100644 index 52afbe75..00000000 --- a/testing/internal/syscall/windows/version_windows_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2024 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 windows_test - -import ( - "errors" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows" - "syscall" - "testing" -) - -func TestSupportUnixSocket(t *testing.T) { - var d syscall.WSAData - if err := syscall.WSAStartup(uint32(0x202), &d); err != nil { - t.Fatal(err) - } - defer syscall.WSACleanup() - - // Test that SupportUnixSocket returns true if WSASocket succeeds with AF_UNIX. - got := windows.SupportUnixSocket() - s, err := windows.WSASocket(syscall.AF_UNIX, syscall.SOCK_STREAM, 0, nil, 0, windows.WSA_FLAG_NO_HANDLE_INHERIT) - if err == nil { - syscall.Closesocket(s) - } - want := !errors.Is(err, windows.WSAEAFNOSUPPORT) && !errors.Is(err, windows.WSAEINVAL) - if want != got { - t.Errorf("SupportUnixSocket = %v; want %v", got, want) - } -} diff --git a/testing/internal/syscall/windows/zsyscall_windows.go b/testing/internal/syscall/windows/zsyscall_windows.go deleted file mode 100644 index 5001bb99..00000000 --- a/testing/internal/syscall/windows/zsyscall_windows.go +++ /dev/null @@ -1,632 +0,0 @@ -// Code generated by 'go generate'; DO NOT EDIT. - -package windows - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows/sysdll" - "syscall" - "unsafe" -) - -var _ unsafe.Pointer - -// Do the interface allocations only once for common -// Errno values. -const ( - errnoERROR_IO_PENDING = 997 -) - -var ( - errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING) - errERROR_EINVAL error = syscall.EINVAL -) - -// errnoErr returns common boxed Errno values, to prevent -// allocations at runtime. -func errnoErr(e syscall.Errno) error { - switch e { - case 0: - return errERROR_EINVAL - case errnoERROR_IO_PENDING: - return errERROR_IO_PENDING - } - // TODO: add more here, after collecting data on the common - // error values see on Windows. (perhaps when running - // all.bat?) - return e -} - -var ( - modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) - modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) - modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) - modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) - modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) - modntdll = syscall.NewLazyDLL(sysdll.Add("ntdll.dll")) - modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) - moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) - modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) - - procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") - procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") - procGetSidIdentifierAuthority = modadvapi32.NewProc("GetSidIdentifierAuthority") - procGetSidSubAuthority = modadvapi32.NewProc("GetSidSubAuthority") - procGetSidSubAuthorityCount = modadvapi32.NewProc("GetSidSubAuthorityCount") - procImpersonateLoggedOnUser = modadvapi32.NewProc("ImpersonateLoggedOnUser") - procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf") - procIsValidSid = modadvapi32.NewProc("IsValidSid") - procLogonUserW = modadvapi32.NewProc("LogonUserW") - procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW") - procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW") - procOpenServiceW = modadvapi32.NewProc("OpenServiceW") - procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") - procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") - procRevertToSelf = modadvapi32.NewProc("RevertToSelf") - procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") - procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") - procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") - procCreateEventW = modkernel32.NewProc("CreateEventW") - procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") - procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") - procGetACP = modkernel32.NewProc("GetACP") - procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") - procGetConsoleCP = modkernel32.NewProc("GetConsoleCP") - procGetCurrentThread = modkernel32.NewProc("GetCurrentThread") - procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") - procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") - procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") - procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW") - procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") - procGetTempPath2W = modkernel32.NewProc("GetTempPath2W") - procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW") - procGetVolumeNameForVolumeMountPointW = modkernel32.NewProc("GetVolumeNameForVolumeMountPointW") - procLockFileEx = modkernel32.NewProc("LockFileEx") - procModule32FirstW = modkernel32.NewProc("Module32FirstW") - procModule32NextW = modkernel32.NewProc("Module32NextW") - procMoveFileExW = modkernel32.NewProc("MoveFileExW") - procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") - procReOpenFile = modkernel32.NewProc("ReOpenFile") - procRtlLookupFunctionEntry = modkernel32.NewProc("RtlLookupFunctionEntry") - procRtlVirtualUnwind = modkernel32.NewProc("RtlVirtualUnwind") - procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle") - procUnlockFileEx = modkernel32.NewProc("UnlockFileEx") - procVirtualQuery = modkernel32.NewProc("VirtualQuery") - procNetShareAdd = modnetapi32.NewProc("NetShareAdd") - procNetShareDel = modnetapi32.NewProc("NetShareDel") - procNetUserAdd = modnetapi32.NewProc("NetUserAdd") - procNetUserDel = modnetapi32.NewProc("NetUserDel") - procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups") - procNtCreateFile = modntdll.NewProc("NtCreateFile") - procNtOpenFile = modntdll.NewProc("NtOpenFile") - procNtQueryInformationFile = modntdll.NewProc("NtQueryInformationFile") - procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") - procRtlGetVersion = modntdll.NewProc("RtlGetVersion") - procRtlIsDosDeviceName_U = modntdll.NewProc("RtlIsDosDeviceName_U") - procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb") - procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") - procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") - procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") - procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW") - procWSADuplicateSocketW = modws2_32.NewProc("WSADuplicateSocketW") - procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") - procWSASocketW = modws2_32.NewProc("WSASocketW") -) - -func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) { - var _p0 uint32 - if disableAllPrivileges { - _p0 = 1 - } - r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen))) - ret = uint32(r0) - if true { - err = errnoErr(e1) - } - return -} - -func DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) { - r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func getSidIdentifierAuthority(sid *syscall.SID) (idauth uintptr) { - r0, _, _ := syscall.Syscall(procGetSidIdentifierAuthority.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) - idauth = uintptr(r0) - return -} - -func getSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) (subAuth uintptr) { - r0, _, _ := syscall.Syscall(procGetSidSubAuthority.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(subAuthorityIdx), 0) - subAuth = uintptr(r0) - return -} - -func getSidSubAuthorityCount(sid *syscall.SID) (count uintptr) { - r0, _, _ := syscall.Syscall(procGetSidSubAuthorityCount.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) - count = uintptr(r0) - return -} - -func ImpersonateLoggedOnUser(token syscall.Token) (err error) { - r1, _, e1 := syscall.Syscall(procImpersonateLoggedOnUser.Addr(), 1, uintptr(token), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ImpersonateSelf(impersonationlevel uint32) (err error) { - r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func IsValidSid(sid *syscall.SID) (valid bool) { - r0, _, _ := syscall.Syscall(procIsValidSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0) - valid = r0 != 0 - return -} - -func LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *syscall.Token) (err error) { - r1, _, e1 := syscall.Syscall6(procLogonUserW.Addr(), 6, uintptr(unsafe.Pointer(username)), uintptr(unsafe.Pointer(domain)), uintptr(unsafe.Pointer(password)), uintptr(logonType), uintptr(logonProvider), uintptr(unsafe.Pointer(token))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) { - r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access)) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access)) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) { - var _p0 uint32 - if openasself { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) { - r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(hService), uintptr(unsafe.Pointer(lpServiceStatus)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func RevertToSelf() (err error) { - r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func ProcessPrng(buf []byte) (err error) { - var _p0 *byte - if len(buf) > 0 { - _p0 = &buf[0] - } - r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetAdaptersAddresses(family uint32, flags uint32, reserved unsafe.Pointer, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) { - r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0) - if r0 != 0 { - errcode = syscall.Errno(r0) - } - return -} - -func CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func CreateIoCompletionPort(filehandle syscall.Handle, cphandle syscall.Handle, key uintptr, threadcnt uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) - handle = syscall.Handle(r0) - if handle == syscall.InvalidHandle { - err = errnoErr(e1) - } - return -} - -func GetACP() (acp uint32) { - r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0) - acp = uint32(r0) - return -} - -func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetConsoleCP() (ccp uint32) { - r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0) - ccp = uint32(r0) - return -} - -func GetCurrentThread() (pseudoHandle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0) - pseudoHandle = syscall.Handle(r0) - if pseudoHandle == 0 { - err = errnoErr(e1) - } - return -} - -func GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(info)), uintptr(bufsize), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len)) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetModuleHandle(modulename *uint16) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modulename)), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func GetOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, done *uint32, wait bool) (err error) { - var _p0 uint32 - if wait { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(done)), uintptr(_p0), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) { - r0, _, e1 := syscall.Syscall(procGetTempPath2W.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) - n = uint32(r0) - if n == 0 { - err = errnoErr(e1) - } - return -} - -func GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { - r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16, bufferlength uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetVolumeNameForVolumeMountPointW.Addr(), 3, uintptr(unsafe.Pointer(volumeMountPoint)), uintptr(unsafe.Pointer(volumeName)), uintptr(bufferlength)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Module32First(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func Module32Next(snapshot syscall.Handle, moduleEntry *ModuleEntry32) (err error) { - r1, _, e1 := syscall.Syscall(procModule32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { - r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) { - r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar)) - nwrite = int32(r0) - if nwrite == 0 { - err = errnoErr(e1) - } - return -} - -func ReOpenFile(filehandle syscall.Handle, desiredAccess uint32, shareMode uint32, flagAndAttributes uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procReOpenFile.Addr(), 4, uintptr(filehandle), uintptr(desiredAccess), uintptr(shareMode), uintptr(flagAndAttributes), 0, 0) - handle = syscall.Handle(r0) - if handle == 0 { - err = errnoErr(e1) - } - return -} - -func RtlLookupFunctionEntry(pc uintptr, baseAddress *uintptr, table unsafe.Pointer) (ret *RUNTIME_FUNCTION) { - r0, _, _ := syscall.Syscall(procRtlLookupFunctionEntry.Addr(), 3, uintptr(pc), uintptr(unsafe.Pointer(baseAddress)), uintptr(table)) - ret = (*RUNTIME_FUNCTION)(unsafe.Pointer(r0)) - return -} - -func RtlVirtualUnwind(handlerType uint32, baseAddress uintptr, pc uintptr, entry *RUNTIME_FUNCTION, ctxt unsafe.Pointer, data unsafe.Pointer, frame *uintptr, ctxptrs unsafe.Pointer) (ret uintptr) { - r0, _, _ := syscall.Syscall9(procRtlVirtualUnwind.Addr(), 8, uintptr(handlerType), uintptr(baseAddress), uintptr(pc), uintptr(unsafe.Pointer(entry)), uintptr(ctxt), uintptr(data), uintptr(unsafe.Pointer(frame)), uintptr(ctxptrs), 0) - ret = uintptr(r0) - return -} - -func SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf unsafe.Pointer, bufsize uint32) (err error) { - r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(handle), uintptr(fileInformationClass), uintptr(buf), uintptr(bufsize), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { - r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) { - r1, _, e1 := syscall.Syscall(procVirtualQuery.Addr(), 3, uintptr(address), uintptr(unsafe.Pointer(buffer)), uintptr(length)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) { - r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) { - r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved)) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetUserAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint32) (neterr error) { - r0, _, _ := syscall.Syscall6(procNetUserAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetUserDel(serverName *uint16, userName *uint16) (neterr error) { - r0, _, _ := syscall.Syscall(procNetUserDel.Addr(), 2, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) { - r0, _, _ := syscall.Syscall9(procNetUserGetLocalGroups.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(flags), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), 0) - if r0 != 0 { - neterr = syscall.Errno(r0) - } - return -} - -func NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer unsafe.Pointer, ealength uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall12(procNtCreateFile.Addr(), 11, uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(allocationSize)), uintptr(attributes), uintptr(share), uintptr(disposition), uintptr(options), uintptr(eabuffer), uintptr(ealength), 0) - if r0 != 0 { - ntstatus = NTStatus(r0) - } - return -} - -func NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtOpenFile.Addr(), 6, uintptr(unsafe.Pointer(handle)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(options)) - if r0 != 0 { - ntstatus = NTStatus(r0) - } - return -} - -func NtQueryInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer unsafe.Pointer, inBufferLen uint32, class uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtQueryInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(inBuffer), uintptr(inBufferLen), uintptr(class), 0) - if r0 != 0 { - ntstatus = NTStatus(r0) - } - return -} - -func NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer unsafe.Pointer, inBufferLen uint32, class uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(inBuffer), uintptr(inBufferLen), uintptr(class), 0) - if r0 != 0 { - ntstatus = NTStatus(r0) - } - return -} - -func rtlGetVersion(info *_OSVERSIONINFOEXW) { - syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) - return -} - -func RtlIsDosDeviceName_U(name *uint16) (ret uint32) { - r0, _, _ := syscall.Syscall(procRtlIsDosDeviceName_U.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0) - ret = uint32(r0) - return -} - -func rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) { - r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(ntstatus), 0, 0) - ret = syscall.Errno(r0) - return -} - -func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) { - var _p0 uint32 - if inheritExisting { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall(procCreateEnvironmentBlock.Addr(), 3, uintptr(unsafe.Pointer(block)), uintptr(token), uintptr(_p0)) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func DestroyEnvironmentBlock(block *uint16) (err error) { - r1, _, e1 := syscall.Syscall(procDestroyEnvironmentBlock.Addr(), 1, uintptr(unsafe.Pointer(block)), 0, 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) { - r1, _, e1 := syscall.Syscall(procGetProfilesDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func WSADuplicateSocket(s syscall.Handle, processID uint32, info *syscall.WSAProtocolInfo) (err error) { - r1, _, e1 := syscall.Syscall(procWSADuplicateSocketW.Addr(), 3, uintptr(s), uintptr(processID), uintptr(unsafe.Pointer(info))) - if r1 != 0 { - err = errnoErr(e1) - } - return -} - -func WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { - var _p0 uint32 - if wait { - _p0 = 1 - } - r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) - if r1 == 0 { - err = errnoErr(e1) - } - return -} - -func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { - r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) - handle = syscall.Handle(r0) - if handle == syscall.InvalidHandle { - err = errnoErr(e1) - } - return -} diff --git a/testing/internal/sysinfo/cpuinfo_bsd.go b/testing/internal/sysinfo/cpuinfo_bsd.go deleted file mode 100644 index 4396a635..00000000 --- a/testing/internal/sysinfo/cpuinfo_bsd.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2023 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 darwin || freebsd || netbsd || openbsd - -package sysinfo - -import "syscall" - -func osCPUInfoName() string { - cpu, _ := syscall.Sysctl("machdep.cpu.brand_string") - return cpu -} diff --git a/testing/internal/sysinfo/cpuinfo_linux.go b/testing/internal/sysinfo/cpuinfo_linux.go deleted file mode 100644 index ae92c51a..00000000 --- a/testing/internal/sysinfo/cpuinfo_linux.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2023 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 sysinfo - -import ( - "bufio" - "bytes" - "io" - "os" - "strings" -) - -func readLinuxProcCPUInfo(buf []byte) error { - f, err := os.Open("/proc/cpuinfo") - if err != nil { - return err - } - defer f.Close() - - _, err = io.ReadFull(f, buf) - if err != nil && err != io.ErrUnexpectedEOF { - return err - } - - return nil -} - -func osCPUInfoName() string { - modelName := "" - cpuMHz := "" - - // The 512-byte buffer is enough to hold the contents of CPU0 - buf := make([]byte, 512) - err := readLinuxProcCPUInfo(buf) - if err != nil { - return "" - } - - scanner := bufio.NewScanner(bytes.NewReader(buf)) - for scanner.Scan() { - key, value, found := strings.Cut(scanner.Text(), ": ") - if !found { - continue - } - switch strings.TrimSpace(key) { - case "Model Name", "model name": - modelName = value - case "CPU MHz", "cpu MHz": - cpuMHz = value - } - } - - if modelName == "" { - return "" - } - - if cpuMHz == "" { - return modelName - } - - // The modelName field already contains the frequency information, - // so the cpuMHz field information is not needed. - // modelName filed example: - // Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz - f := [...]string{"GHz", "MHz"} - for _, v := range f { - if strings.Contains(modelName, v) { - return modelName - } - } - - return modelName + " @ " + cpuMHz + "MHz" -} diff --git a/testing/internal/sysinfo/cpuinfo_stub.go b/testing/internal/sysinfo/cpuinfo_stub.go deleted file mode 100644 index 2ac7ffaf..00000000 --- a/testing/internal/sysinfo/cpuinfo_stub.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2023 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 !(darwin || freebsd || linux || netbsd || openbsd) - -package sysinfo - -func osCPUInfoName() string { - return "" -} diff --git a/testing/internal/sysinfo/export_test.go b/testing/internal/sysinfo/export_test.go deleted file mode 100644 index 809a6837..00000000 --- a/testing/internal/sysinfo/export_test.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2023 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 sysinfo - -var XosCPUInfoName = osCPUInfoName diff --git a/testing/internal/sysinfo/sysinfo.go b/testing/internal/sysinfo/sysinfo.go deleted file mode 100644 index 2d943f12..00000000 --- a/testing/internal/sysinfo/sysinfo.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 sysinfo implements high level hardware information gathering -// that can be used for debugging or information purposes. -package sysinfo - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/cpu" - "sync" -) - -var CPUName = sync.OnceValue(func() string { - if name := cpu.Name(); name != "" { - return name - } - - if name := osCPUInfoName(); name != "" { - return name - } - - return "" -}) diff --git a/testing/internal/sysinfo/sysinfo_test.go b/testing/internal/sysinfo/sysinfo_test.go deleted file mode 100644 index 87ce0207..00000000 --- a/testing/internal/sysinfo/sysinfo_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2023 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 sysinfo_test - -import ( - . "github.com/CodSpeedHQ/codspeed-go/testing/internal/sysinfo" - "testing" -) - -func TestCPUName(t *testing.T) { - t.Logf("CPUName: %s", CPUName()) - t.Logf("osCPUInfoName: %s", XosCPUInfoName()) -} diff --git a/testing/internal/testenv/exec.go b/testing/internal/testenv/exec.go deleted file mode 100644 index 5b879573..00000000 --- a/testing/internal/testenv/exec.go +++ /dev/null @@ -1,242 +0,0 @@ -// 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 testenv - -import ( - "context" - "errors" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "os" - "os/exec" - "runtime" - "strconv" - "strings" - "sync" - "time" -) - -// MustHaveExec checks that the current system can start new processes -// using os.StartProcess or (more commonly) exec.Command. -// If not, MustHaveExec calls t.Skip with an explanation. -// -// On some platforms MustHaveExec checks for exec support by re-executing the -// current executable, which must be a binary built by 'go test'. -// We intentionally do not provide a HasExec function because of the risk of -// inappropriate recursion in TestMain functions. -// -// To check for exec support outside of a test, just try to exec the command. -// If exec is not supported, testenv.SyscallIsNotSupported will return true -// for the resulting error. -func MustHaveExec(t testing.TB) { - if err := tryExec(); err != nil { - msg := fmt.Sprintf("cannot exec subprocess on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err) - if t == nil { - panic(msg) - } - t.Helper() - t.Skip("skipping test:", msg) - } -} - -var tryExec = sync.OnceValue(func() error { - switch runtime.GOOS { - case "wasip1", "js", "ios": - default: - // Assume that exec always works on non-mobile platforms and Android. - return nil - } - - // ios has an exec syscall but on real iOS devices it might return a - // permission error. In an emulated environment (such as a Corellium host) - // it might succeed, so if we need to exec we'll just have to try it and - // find out. - // - // As of 2023-04-19 wasip1 and js don't have exec syscalls at all, but we - // may as well use the same path so that this branch can be tested without - // an ios environment. - - if !testing.Testing() { - // This isn't a standard 'go test' binary, so we don't know how to - // self-exec in a way that should succeed without side effects. - // Just forget it. - return errors.New("can't probe for exec support with a non-test executable") - } - - // We know that this is a test executable. We should be able to run it with a - // no-op flag to check for overall exec support. - exe, err := exePath() - if err != nil { - return fmt.Errorf("can't probe for exec support: %w", err) - } - cmd := exec.Command(exe, "-test.list=^$") - cmd.Env = origEnv - return cmd.Run() -}) - -// Executable is a wrapper around [MustHaveExec] and [os.Executable]. -// It returns the path name for the executable that started the current process, -// or skips the test if the current system can't start new processes, -// or fails the test if the path can not be obtained. -func Executable(t testing.TB) string { - MustHaveExec(t) - - exe, err := exePath() - if err != nil { - msg := fmt.Sprintf("os.Executable error: %v", err) - if t == nil { - panic(msg) - } - t.Fatal(msg) - } - return exe -} - -var exePath = sync.OnceValues(func() (string, error) { - return os.Executable() -}) - -var execPaths sync.Map // path -> error - -// MustHaveExecPath checks that the current system can start the named executable -// using os.StartProcess or (more commonly) exec.Command. -// If not, MustHaveExecPath calls t.Skip with an explanation. -func MustHaveExecPath(t testing.TB, path string) { - MustHaveExec(t) - - err, found := execPaths.Load(path) - if !found { - _, err = exec.LookPath(path) - err, _ = execPaths.LoadOrStore(path, err) - } - if err != nil { - t.Helper() - t.Skipf("skipping test: %s: %s", path, err) - } -} - -// CleanCmdEnv will fill cmd.Env with the environment, excluding certain -// variables that could modify the behavior of the Go tools such as -// GODEBUG and GOTRACEBACK. -// -// If the caller wants to set cmd.Dir, set it before calling this function, -// so PWD will be set correctly in the environment. -func CleanCmdEnv(cmd *exec.Cmd) *exec.Cmd { - if cmd.Env != nil { - panic("environment already set") - } - for _, env := range cmd.Environ() { - // Exclude GODEBUG from the environment to prevent its output - // from breaking tests that are trying to parse other command output. - if strings.HasPrefix(env, "GODEBUG=") { - continue - } - // Exclude GOTRACEBACK for the same reason. - if strings.HasPrefix(env, "GOTRACEBACK=") { - continue - } - cmd.Env = append(cmd.Env, env) - } - return cmd -} - -// CommandContext is like exec.CommandContext, but: -// - skips t if the platform does not support os/exec, -// - sends SIGQUIT (if supported by the platform) instead of SIGKILL -// in its Cancel function -// - if the test has a deadline, adds a Context timeout and WaitDelay -// for an arbitrary grace period before the test's deadline expires, -// - fails the test if the command does not complete before the test's deadline, and -// - sets a Cleanup function that verifies that the test did not leak a subprocess. -func CommandContext(t testing.TB, ctx context.Context, name string, args ...string) *exec.Cmd { - t.Helper() - MustHaveExec(t) - - var ( - cancelCtx context.CancelFunc - gracePeriod time.Duration // unlimited unless the test has a deadline (to allow for interactive debugging) - ) - - if t, ok := t.(interface { - testing.TB - Deadline() (time.Time, bool) - }); ok { - if td, ok := t.Deadline(); ok { - // Start with a minimum grace period, just long enough to consume the - // output of a reasonable program after it terminates. - gracePeriod = 100 * time.Millisecond - if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" { - scale, err := strconv.Atoi(s) - if err != nil { - t.Fatalf("invalid GO_TEST_TIMEOUT_SCALE: %v", err) - } - gracePeriod *= time.Duration(scale) - } - - // If time allows, increase the termination grace period to 5% of the - // test's remaining time. - testTimeout := time.Until(td) - if gp := testTimeout / 20; gp > gracePeriod { - gracePeriod = gp - } - - // When we run commands that execute subprocesses, we want to reserve two - // grace periods to clean up: one for the delay between the first - // termination signal being sent (via the Cancel callback when the Context - // expires) and the process being forcibly terminated (via the WaitDelay - // field), and a second one for the delay between the process being - // terminated and the test logging its output for debugging. - // - // (We want to ensure that the test process itself has enough time to - // log the output before it is also terminated.) - cmdTimeout := testTimeout - 2*gracePeriod - - if cd, ok := ctx.Deadline(); !ok || time.Until(cd) > cmdTimeout { - // Either ctx doesn't have a deadline, or its deadline would expire - // after (or too close before) the test has already timed out. - // Add a shorter timeout so that the test will produce useful output. - ctx, cancelCtx = context.WithTimeout(ctx, cmdTimeout) - } - } - } - - cmd := exec.CommandContext(ctx, name, args...) - cmd.Cancel = func() error { - if cancelCtx != nil && ctx.Err() == context.DeadlineExceeded { - // The command timed out due to running too close to the test's deadline. - // There is no way the test did that intentionally — it's too close to the - // wire! — so mark it as a test failure. That way, if the test expects the - // command to fail for some other reason, it doesn't have to distinguish - // between that reason and a timeout. - t.Errorf("test timed out while running command: %v", cmd) - } else { - // The command is being terminated due to ctx being canceled, but - // apparently not due to an explicit test deadline that we added. - // Log that information in case it is useful for diagnosing a failure, - // but don't actually fail the test because of it. - t.Logf("%v: terminating command: %v", ctx.Err(), cmd) - } - return cmd.Process.Signal(Sigquit) - } - cmd.WaitDelay = gracePeriod - - t.Cleanup(func() { - if cancelCtx != nil { - cancelCtx() - } - if cmd.Process != nil && cmd.ProcessState == nil { - t.Errorf("command was started, but test did not wait for it to complete: %v", cmd) - } - }) - - return cmd -} - -// Command is like exec.Command, but applies the same changes as -// testenv.CommandContext (with a default Context). -func Command(t testing.TB, name string, args ...string) *exec.Cmd { - t.Helper() - return CommandContext(t, context.Background(), name, args...) -} diff --git a/testing/internal/testenv/noopt.go b/testing/internal/testenv/noopt.go deleted file mode 100644 index ae2a3d01..00000000 --- a/testing/internal/testenv/noopt.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2022 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 noopt - -package testenv - -// OptimizationOff reports whether optimization is disabled. -func OptimizationOff() bool { - return true -} diff --git a/testing/internal/testenv/opt.go b/testing/internal/testenv/opt.go deleted file mode 100644 index 1bb96f73..00000000 --- a/testing/internal/testenv/opt.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2022 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 !noopt - -package testenv - -// OptimizationOff reports whether optimization is disabled. -func OptimizationOff() bool { - return false -} diff --git a/testing/internal/testenv/testenv.go b/testing/internal/testenv/testenv.go deleted file mode 100644 index d239840d..00000000 --- a/testing/internal/testenv/testenv.go +++ /dev/null @@ -1,543 +0,0 @@ -// 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 testenv provides information about what functionality -// is available in different testing environments run by the Go team. -// -// It is an internal package because these details are specific -// to the Go team's test setup (on build.golang.org) and not -// fundamental to tests in general. -package testenv - -import ( - "bytes" - "errors" - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/cfg" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/goarch" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/platform" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "os" - "os/exec" - "path/filepath" - "runtime" - "strconv" - "strings" - "sync" -) - -// Save the original environment during init for use in checks. A test -// binary may modify its environment before calling HasExec to change its -// behavior (such as mimicking a command-line tool), and that modified -// environment might cause environment checks to behave erratically. -var origEnv = os.Environ() - -// Builder reports the name of the builder running this test -// (for example, "linux-amd64" or "windows-386-gce"). -// If the test is not running on the build infrastructure, -// Builder returns the empty string. -func Builder() string { - return os.Getenv("GO_BUILDER_NAME") -} - -// HasGoBuild reports whether the current system can build programs with “go build” -// and then run them with os.StartProcess or exec.Command. -func HasGoBuild() bool { - if os.Getenv("GO_GCFLAGS") != "" { - // It's too much work to require every caller of the go command - // to pass along "-gcflags="+os.Getenv("GO_GCFLAGS"). - // For now, if $GO_GCFLAGS is set, report that we simply can't - // run go build. - return false - } - - return tryGoBuild() == nil -} - -var tryGoBuild = sync.OnceValue(func() error { - // To run 'go build', we need to be able to exec a 'go' command. - // We somewhat arbitrarily choose to exec 'go tool -n compile' because that - // also confirms that cmd/go can find the compiler. (Before CL 472096, - // we sometimes ended up with cmd/go installed in the test environment - // without a cmd/compile it could use to actually build things.) - goTool, err := goTool() - if err != nil { - return err - } - cmd := exec.Command(goTool, "tool", "-n", "compile") - cmd.Env = origEnv - out, err := cmd.Output() - if err != nil { - return fmt.Errorf("%v: %w", cmd, err) - } - out = bytes.TrimSpace(out) - if len(out) == 0 { - return fmt.Errorf("%v: no tool reported", cmd) - } - if _, err := exec.LookPath(string(out)); err != nil { - return err - } - - if platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) { - // We can assume that we always have a complete Go toolchain available. - // However, this platform requires a C linker to build even pure Go - // programs, including tests. Do we have one in the test environment? - // (On Android, for example, the device running the test might not have a - // C toolchain installed.) - // - // If CC is set explicitly, assume that we do. Otherwise, use 'go env CC' - // to determine which toolchain it would use by default. - if os.Getenv("CC") == "" { - cmd := exec.Command(goTool, "env", "CC") - cmd.Env = origEnv - out, err := cmd.Output() - if err != nil { - return fmt.Errorf("%v: %w", cmd, err) - } - out = bytes.TrimSpace(out) - if len(out) == 0 { - return fmt.Errorf("%v: no CC reported", cmd) - } - _, err = exec.LookPath(string(out)) - return err - } - } - return nil -}) - -// MustHaveGoBuild checks that the current system can build programs with “go build” -// and then run them with os.StartProcess or exec.Command. -// If not, MustHaveGoBuild calls t.Skip with an explanation. -func MustHaveGoBuild(t testing.TB) { - if os.Getenv("GO_GCFLAGS") != "" { - t.Helper() - t.Skipf("skipping test: 'go build' not compatible with setting $GO_GCFLAGS") - } - if !HasGoBuild() { - t.Helper() - t.Skipf("skipping test: 'go build' unavailable: %v", tryGoBuild()) - } -} - -// HasGoRun reports whether the current system can run programs with “go run”. -func HasGoRun() bool { - // For now, having go run and having go build are the same. - return HasGoBuild() -} - -// MustHaveGoRun checks that the current system can run programs with “go run”. -// If not, MustHaveGoRun calls t.Skip with an explanation. -func MustHaveGoRun(t testing.TB) { - if !HasGoRun() { - t.Helper() - t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH) - } -} - -// HasParallelism reports whether the current system can execute multiple -// threads in parallel. -// There is a copy of this function in cmd/dist/test.go. -func HasParallelism() bool { - switch runtime.GOOS { - case "js", "wasip1": - return false - } - return true -} - -// MustHaveParallelism checks that the current system can execute multiple -// threads in parallel. If not, MustHaveParallelism calls t.Skip with an explanation. -func MustHaveParallelism(t testing.TB) { - if !HasParallelism() { - t.Helper() - t.Skipf("skipping test: no parallelism available on %s/%s", runtime.GOOS, runtime.GOARCH) - } -} - -// GoToolPath reports the path to the Go tool. -// It is a convenience wrapper around GoTool. -// If the tool is unavailable GoToolPath calls t.Skip. -// If the tool should be available and isn't, GoToolPath calls t.Fatal. -func GoToolPath(t testing.TB) string { - MustHaveGoBuild(t) - path, err := GoTool() - if err != nil { - t.Fatal(err) - } - // Add all environment variables that affect the Go command to test metadata. - // Cached test results will be invalidate when these variables change. - // See golang.org/issue/32285. - for _, envVar := range strings.Fields(cfg.KnownEnv) { - os.Getenv(envVar) - } - return path -} - -var findGOROOT = sync.OnceValues(func() (path string, err error) { - if path := runtime.GOROOT(); path != "" { - // If runtime.GOROOT() is non-empty, assume that it is valid. - // - // (It might not be: for example, the user may have explicitly set GOROOT - // to the wrong directory. But this case is - // rare, and if that happens the user can fix what they broke.) - return path, nil - } - - // runtime.GOROOT doesn't know where GOROOT is (perhaps because the test - // binary was built with -trimpath). - // - // Since this is internal/testenv, we can cheat and assume that the caller - // is a test of some package in a subdirectory of GOROOT/src. ('go test' - // runs the test in the directory containing the packaged under test.) That - // means that if we start walking up the tree, we should eventually find - // GOROOT/src/go.mod, and we can report the parent directory of that. - // - // Notably, this works even if we can't run 'go env GOROOT' as a - // subprocess. - - cwd, err := os.Getwd() - if err != nil { - return "", fmt.Errorf("finding GOROOT: %w", err) - } - - dir := cwd - for { - parent := filepath.Dir(dir) - if parent == dir { - // dir is either "." or only a volume name. - return "", fmt.Errorf("failed to locate GOROOT/src in any parent directory") - } - - if base := filepath.Base(dir); base != "src" { - dir = parent - continue // dir cannot be GOROOT/src if it doesn't end in "src". - } - - b, err := os.ReadFile(filepath.Join(dir, "go.mod")) - if err != nil { - if os.IsNotExist(err) { - dir = parent - continue - } - return "", fmt.Errorf("finding GOROOT: %w", err) - } - goMod := string(b) - - for goMod != "" { - var line string - line, goMod, _ = strings.Cut(goMod, "\n") - fields := strings.Fields(line) - if len(fields) >= 2 && fields[0] == "module" && fields[1] == "std" { - // Found "module std", which is the module declaration in GOROOT/src! - return parent, nil - } - } - } -}) - -// GOROOT reports the path to the directory containing the root of the Go -// project source tree. This is normally equivalent to runtime.GOROOT, but -// works even if the test binary was built with -trimpath and cannot exec -// 'go env GOROOT'. -// -// If GOROOT cannot be found, GOROOT skips t if t is non-nil, -// or panics otherwise. -func GOROOT(t testing.TB) string { - path, err := findGOROOT() - if err != nil { - if t == nil { - panic(err) - } - t.Helper() - t.Skip(err) - } - return path -} - -// GoTool reports the path to the Go tool. -func GoTool() (string, error) { - if !HasGoBuild() { - return "", errors.New("platform cannot run go tool") - } - return goTool() -} - -var goTool = sync.OnceValues(func() (string, error) { - return exec.LookPath("go") -}) - -// MustHaveSource checks that the entire source tree is available under GOROOT. -// If not, it calls t.Skip with an explanation. -func MustHaveSource(t testing.TB) { - switch runtime.GOOS { - case "ios": - t.Helper() - t.Skip("skipping test: no source tree on " + runtime.GOOS) - } -} - -// HasExternalNetwork reports whether the current system can use -// external (non-localhost) networks. -func HasExternalNetwork() bool { - return !testing.Short() && runtime.GOOS != "js" && runtime.GOOS != "wasip1" -} - -// MustHaveExternalNetwork checks that the current system can use -// external (non-localhost) networks. -// If not, MustHaveExternalNetwork calls t.Skip with an explanation. -func MustHaveExternalNetwork(t testing.TB) { - if runtime.GOOS == "js" || runtime.GOOS == "wasip1" { - t.Helper() - t.Skipf("skipping test: no external network on %s", runtime.GOOS) - } - if testing.Short() { - t.Helper() - t.Skipf("skipping test: no external network in -short mode") - } -} - -// HasCGO reports whether the current system can use cgo. -func HasCGO() bool { - return hasCgo() -} - -var hasCgo = sync.OnceValue(func() bool { - goTool, err := goTool() - if err != nil { - return false - } - cmd := exec.Command(goTool, "env", "CGO_ENABLED") - cmd.Env = origEnv - out, err := cmd.Output() - if err != nil { - panic(fmt.Sprintf("%v: %v", cmd, out)) - } - ok, err := strconv.ParseBool(string(bytes.TrimSpace(out))) - if err != nil { - panic(fmt.Sprintf("%v: non-boolean output %q", cmd, out)) - } - return ok -}) - -// MustHaveCGO calls t.Skip if cgo is not available. -func MustHaveCGO(t testing.TB) { - if !HasCGO() { - t.Helper() - t.Skipf("skipping test: no cgo") - } -} - -// CanInternalLink reports whether the current system can link programs with -// internal linking. -func CanInternalLink(withCgo bool) bool { - return !platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, withCgo) -} - -// SpecialBuildTypes are interesting build types that may affect linking. -type SpecialBuildTypes struct { - Cgo bool - Asan bool - Msan bool - Race bool -} - -// NoSpecialBuildTypes indicates a standard, no cgo go build. -var NoSpecialBuildTypes SpecialBuildTypes - -// MustInternalLink checks that the current system can link programs with internal -// linking. -// If not, MustInternalLink calls t.Skip with an explanation. -func MustInternalLink(t testing.TB, with SpecialBuildTypes) { - if with.Asan || with.Msan || with.Race { - t.Skipf("skipping test: internal linking with sanitizers is not supported") - } - if !CanInternalLink(with.Cgo) { - t.Helper() - if with.Cgo && CanInternalLink(false) { - t.Skipf("skipping test: internal linking on %s/%s is not supported with cgo", runtime.GOOS, runtime.GOARCH) - } - t.Skipf("skipping test: internal linking on %s/%s is not supported", runtime.GOOS, runtime.GOARCH) - } -} - -// MustInternalLinkPIE checks whether the current system can link PIE binary using -// internal linking. -// If not, MustInternalLinkPIE calls t.Skip with an explanation. -func MustInternalLinkPIE(t testing.TB) { - if !platform.InternalLinkPIESupported(runtime.GOOS, runtime.GOARCH) { - t.Helper() - t.Skipf("skipping test: internal linking for buildmode=pie on %s/%s is not supported", runtime.GOOS, runtime.GOARCH) - } -} - -// MustHaveBuildMode reports whether the current system can build programs in -// the given build mode. -// If not, MustHaveBuildMode calls t.Skip with an explanation. -func MustHaveBuildMode(t testing.TB, buildmode string) { - if !platform.BuildModeSupported(runtime.Compiler, buildmode, runtime.GOOS, runtime.GOARCH) { - t.Helper() - t.Skipf("skipping test: build mode %s on %s/%s is not supported by the %s compiler", buildmode, runtime.GOOS, runtime.GOARCH, runtime.Compiler) - } -} - -// HasSymlink reports whether the current system can use os.Symlink. -func HasSymlink() bool { - ok, _ := hasSymlink() - return ok -} - -// MustHaveSymlink reports whether the current system can use os.Symlink. -// If not, MustHaveSymlink calls t.Skip with an explanation. -func MustHaveSymlink(t testing.TB) { - ok, reason := hasSymlink() - if !ok { - t.Helper() - t.Skipf("skipping test: cannot make symlinks on %s/%s: %s", runtime.GOOS, runtime.GOARCH, reason) - } -} - -// HasLink reports whether the current system can use os.Link. -func HasLink() bool { - // From Android release M (Marshmallow), hard linking files is blocked - // and an attempt to call link() on a file will return EACCES. - // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150 - return runtime.GOOS != "plan9" && runtime.GOOS != "android" -} - -// MustHaveLink reports whether the current system can use os.Link. -// If not, MustHaveLink calls t.Skip with an explanation. -func MustHaveLink(t testing.TB) { - if !HasLink() { - t.Helper() - t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH) - } -} - -var flaky = flag.Bool("flaky", false, "run known-flaky tests too") - -func SkipFlaky(t testing.TB, issue int) { - if !*flaky { - t.Helper() - t.Skipf("skipping known flaky test without the -flaky flag; see golang.org/issue/%d", issue) - } -} - -func SkipFlakyNet(t testing.TB) { - if v, _ := strconv.ParseBool(os.Getenv("GO_BUILDER_FLAKY_NET")); v { - t.Helper() - t.Skip("skipping test on builder known to have frequent network failures") - } -} - -// CPUIsSlow reports whether the CPU running the test is suspected to be slow. -func CPUIsSlow() bool { - switch runtime.GOARCH { - case "arm", "mips", "mipsle", "mips64", "mips64le", "wasm": - return true - } - return false -} - -// SkipIfShortAndSlow skips t if -short is set and the CPU running the test is -// suspected to be slow. -// -// (This is useful for CPU-intensive tests that otherwise complete quickly.) -func SkipIfShortAndSlow(t testing.TB) { - if testing.Short() && CPUIsSlow() { - t.Helper() - t.Skipf("skipping test in -short mode on %s", runtime.GOARCH) - } -} - -// SkipIfOptimizationOff skips t if optimization is disabled. -func SkipIfOptimizationOff(t testing.TB) { - if OptimizationOff() { - t.Helper() - t.Skip("skipping test with optimization disabled") - } -} - -// WriteImportcfg writes an importcfg file used by the compiler or linker to -// dstPath containing entries for the file mappings in packageFiles, as well -// as for the packages transitively imported by the package(s) in pkgs. -// -// pkgs may include any package pattern that is valid to pass to 'go list', -// so it may also be a list of Go source files all in the same directory. -func WriteImportcfg(t testing.TB, dstPath string, packageFiles map[string]string, pkgs ...string) { - t.Helper() - - icfg := new(bytes.Buffer) - icfg.WriteString("# import config\n") - for k, v := range packageFiles { - fmt.Fprintf(icfg, "packagefile %s=%s\n", k, v) - } - - if len(pkgs) > 0 { - // Use 'go list' to resolve any missing packages and rewrite the import map. - cmd := Command(t, GoToolPath(t), "list", "-export", "-deps", "-f", `{{if ne .ImportPath "command-line-arguments"}}{{if .Export}}{{.ImportPath}}={{.Export}}{{end}}{{end}}`) - cmd.Args = append(cmd.Args, pkgs...) - cmd.Stderr = new(strings.Builder) - out, err := cmd.Output() - if err != nil { - t.Fatalf("%v: %v\n%s", cmd, err, cmd.Stderr) - } - - for _, line := range strings.Split(string(out), "\n") { - if line == "" { - continue - } - importPath, export, ok := strings.Cut(line, "=") - if !ok { - t.Fatalf("invalid line in output from %v:\n%s", cmd, line) - } - if packageFiles[importPath] == "" { - fmt.Fprintf(icfg, "packagefile %s=%s\n", importPath, export) - } - } - } - - if err := os.WriteFile(dstPath, icfg.Bytes(), 0666); err != nil { - t.Fatal(err) - } -} - -// SyscallIsNotSupported reports whether err may indicate that a system call is -// not supported by the current platform or execution environment. -func SyscallIsNotSupported(err error) bool { - return syscallIsNotSupported(err) -} - -// ParallelOn64Bit calls t.Parallel() unless there is a case that cannot be parallel. -// This function should be used when it is necessary to avoid t.Parallel on -// 32-bit machines, typically because the test uses lots of memory. -func ParallelOn64Bit(t *testing.T) { - if goarch.PtrSize == 4 { - return - } - t.Parallel() -} - -// CPUProfilingBroken returns true if CPU profiling has known issues on this -// platform. -func CPUProfilingBroken() bool { - switch runtime.GOOS { - case "plan9": - // Profiling unimplemented. - return true - case "aix": - // See https://golang.org/issue/45170. - return true - case "ios", "dragonfly", "netbsd", "illumos", "solaris": - // See https://golang.org/issue/13841. - return true - case "openbsd": - if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" { - // See https://golang.org/issue/13841. - return true - } - } - - return false -} diff --git a/testing/internal/testenv/testenv_notunix.go b/testing/internal/testenv/testenv_notunix.go deleted file mode 100644 index a7df5f5d..00000000 --- a/testing/internal/testenv/testenv_notunix.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2021 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 windows || plan9 || (js && wasm) || wasip1 - -package testenv - -import ( - "errors" - "io/fs" - "os" -) - -// Sigquit is the signal to send to kill a hanging subprocess. -// On Unix we send SIGQUIT, but on non-Unix we only have os.Kill. -var Sigquit = os.Kill - -func syscallIsNotSupported(err error) bool { - return errors.Is(err, fs.ErrPermission) || errors.Is(err, errors.ErrUnsupported) -} diff --git a/testing/internal/testenv/testenv_notwin.go b/testing/internal/testenv/testenv_notwin.go deleted file mode 100644 index 9dddea94..00000000 --- a/testing/internal/testenv/testenv_notwin.go +++ /dev/null @@ -1,47 +0,0 @@ -// 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. - -//go:build !windows - -package testenv - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "sync" -) - -var hasSymlink = sync.OnceValues(func() (ok bool, reason string) { - switch runtime.GOOS { - case "plan9": - return false, "" - case "android", "wasip1": - // For wasip1, some runtimes forbid absolute symlinks, - // or symlinks that escape the current working directory. - // Perform a simple test to see whether the runtime - // supports symlinks or not. If we get a permission - // error, the runtime does not support symlinks. - dir, err := os.MkdirTemp("", "") - if err != nil { - return false, "" - } - defer func() { - _ = os.RemoveAll(dir) - }() - fpath := filepath.Join(dir, "testfile.txt") - if err := os.WriteFile(fpath, nil, 0644); err != nil { - return false, "" - } - if err := os.Symlink(fpath, filepath.Join(dir, "testlink")); err != nil { - if SyscallIsNotSupported(err) { - return false, fmt.Sprintf("symlinks unsupported: %s", err.Error()) - } - return false, "" - } - } - - return true, "" -}) diff --git a/testing/internal/testenv/testenv_test.go b/testing/internal/testenv/testenv_test.go deleted file mode 100644 index 7dbbdb64..00000000 --- a/testing/internal/testenv/testenv_test.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2022 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 testenv_test - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/platform" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "path/filepath" - "runtime" - "strings" - "testing" -) - -func TestGoToolLocation(t *testing.T) { - testenv.MustHaveGoBuild(t) - - var exeSuffix string - if runtime.GOOS == "windows" { - exeSuffix = ".exe" - } - - // Tests are defined to run within their package source directory, - // and this package's source directory is $GOROOT/src/internal/testenv. - // The 'go' command is installed at $GOROOT/bin/go, so if the environment - // is correct then testenv.GoTool() should be identical to ../../../bin/go. - - relWant := "../../../bin/go" + exeSuffix - absWant, err := filepath.Abs(relWant) - if err != nil { - t.Fatal(err) - } - - wantInfo, err := os.Stat(absWant) - if err != nil { - t.Fatal(err) - } - t.Logf("found go tool at %q (%q)", relWant, absWant) - - goTool, err := testenv.GoTool() - if err != nil { - t.Fatalf("testenv.GoTool(): %v", err) - } - t.Logf("testenv.GoTool() = %q", goTool) - - gotInfo, err := os.Stat(goTool) - if err != nil { - t.Fatal(err) - } - if !os.SameFile(wantInfo, gotInfo) { - t.Fatalf("%q is not the same file as %q", absWant, goTool) - } -} - -func TestHasGoBuild(t *testing.T) { - if !testenv.HasGoBuild() { - switch runtime.GOOS { - case "js", "wasip1": - // No exec syscall, so these shouldn't be able to 'go build'. - t.Logf("HasGoBuild is false on %s", runtime.GOOS) - return - } - - b := testenv.Builder() - if b == "" { - // We shouldn't make assumptions about what kind of sandbox or build - // environment external Go users may be running in. - t.Skipf("skipping: 'go build' unavailable") - } - - // Since we control the Go builders, we know which ones ought - // to be able to run 'go build'. Check that they can. - // - // (Note that we don't verify that any builders *can't* run 'go build'. - // If a builder starts running 'go build' tests when it shouldn't, - // we will presumably find out about it when those tests fail.) - switch runtime.GOOS { - case "ios": - if isCorelliumBuilder(b) { - // The corellium environment is self-hosting, so it should be able - // to build even though real "ios" devices can't exec. - } else { - // The usual iOS sandbox does not allow the app to start another - // process. If we add builders on stock iOS devices, they presumably - // will not be able to exec, so we may as well allow that now. - t.Logf("HasGoBuild is false on %s", b) - return - } - case "android": - if isEmulatedBuilder(b) && platform.MustLinkExternal(runtime.GOOS, runtime.GOARCH, false) { - // As of 2023-05-02, the test environment on the emulated builders is - // missing a C linker. - t.Logf("HasGoBuild is false on %s", b) - return - } - } - - if strings.Contains(b, "-noopt") { - // The -noopt builder sets GO_GCFLAGS, which causes tests of 'go build' to - // be skipped. - t.Logf("HasGoBuild is false on %s", b) - return - } - - t.Fatalf("HasGoBuild unexpectedly false on %s", b) - } - - t.Logf("HasGoBuild is true; checking consistency with other functions") - - hasExec := false - hasExecGo := false - t.Run("MustHaveExec", func(t *testing.T) { - testenv.MustHaveExec(t) - hasExec = true - }) - t.Run("MustHaveExecPath", func(t *testing.T) { - testenv.MustHaveExecPath(t, "go") - hasExecGo = true - }) - if !hasExec { - t.Errorf(`MustHaveExec(t) skipped unexpectedly`) - } - if !hasExecGo { - t.Errorf(`MustHaveExecPath(t, "go") skipped unexpectedly`) - } - - dir := t.TempDir() - mainGo := filepath.Join(dir, "main.go") - if err := os.WriteFile(mainGo, []byte("package main\nfunc main() {}\n"), 0644); err != nil { - t.Fatal(err) - } - cmd := testenv.Command(t, "go", "build", "-o", os.DevNull, mainGo) - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%v: %v\n%s", cmd, err, out) - } -} - -func TestMustHaveExec(t *testing.T) { - hasExec := false - t.Run("MustHaveExec", func(t *testing.T) { - testenv.MustHaveExec(t) - t.Logf("MustHaveExec did not skip") - hasExec = true - }) - - switch runtime.GOOS { - case "js", "wasip1": - if hasExec { - // js and wasip1 lack an “exec” syscall. - t.Errorf("expected MustHaveExec to skip on %v", runtime.GOOS) - } - case "ios": - if b := testenv.Builder(); isCorelliumBuilder(b) && !hasExec { - // Most ios environments can't exec, but the corellium builder can. - t.Errorf("expected MustHaveExec not to skip on %v", b) - } - default: - if b := testenv.Builder(); b != "" && !hasExec { - t.Errorf("expected MustHaveExec not to skip on %v", b) - } - } -} - -func TestCleanCmdEnvPWD(t *testing.T) { - // Test that CleanCmdEnv sets PWD if cmd.Dir is set. - switch runtime.GOOS { - case "plan9", "windows": - t.Skipf("PWD is not used on %s", runtime.GOOS) - } - dir := t.TempDir() - cmd := testenv.Command(t, testenv.GoToolPath(t), "help") - cmd.Dir = dir - cmd = testenv.CleanCmdEnv(cmd) - - for _, env := range cmd.Env { - if strings.HasPrefix(env, "PWD=") { - pwd := strings.TrimPrefix(env, "PWD=") - if pwd != dir { - t.Errorf("unexpected PWD: want %s, got %s", dir, pwd) - } - return - } - } - t.Error("PWD not set in cmd.Env") -} - -func isCorelliumBuilder(builderName string) bool { - // Support both the old infra's builder names and the LUCI builder names. - // The former's names are ad-hoc so we could maintain this invariant on - // the builder side. The latter's names are structured, and "corellium" will - // appear as a "host" suffix after the GOOS and GOARCH, which always begin - // with an underscore. - return strings.HasSuffix(builderName, "-corellium") || strings.Contains(builderName, "_corellium") -} - -func isEmulatedBuilder(builderName string) bool { - // Support both the old infra's builder names and the LUCI builder names. - // The former's names are ad-hoc so we could maintain this invariant on - // the builder side. The latter's names are structured, and the signifier - // of emulation "emu" will appear as a "host" suffix after the GOOS and - // GOARCH because it modifies the run environment in such a way that it - // the target GOOS and GOARCH may not match the host. This suffix always - // begins with an underscore. - return strings.HasSuffix(builderName, "-emu") || strings.Contains(builderName, "_emu") -} diff --git a/testing/internal/testenv/testenv_unix.go b/testing/internal/testenv/testenv_unix.go deleted file mode 100644 index a6290788..00000000 --- a/testing/internal/testenv/testenv_unix.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2021 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 testenv - -import ( - "errors" - "io/fs" - "syscall" -) - -// Sigquit is the signal to send to kill a hanging subprocess. -// Send SIGQUIT to get a stack trace. -var Sigquit = syscall.SIGQUIT - -func syscallIsNotSupported(err error) bool { - if err == nil { - return false - } - - var errno syscall.Errno - if errors.As(err, &errno) { - switch errno { - case syscall.EPERM, syscall.EROFS: - // User lacks permission: either the call requires root permission and the - // user is not root, or the call is denied by a container security policy. - return true - case syscall.EINVAL: - // Some containers return EINVAL instead of EPERM if a system call is - // denied by security policy. - return true - } - } - - if errors.Is(err, fs.ErrPermission) || errors.Is(err, errors.ErrUnsupported) { - return true - } - - return false -} diff --git a/testing/internal/testenv/testenv_windows.go b/testing/internal/testenv/testenv_windows.go deleted file mode 100644 index eed53cdf..00000000 --- a/testing/internal/testenv/testenv_windows.go +++ /dev/null @@ -1,32 +0,0 @@ -// 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 testenv - -import ( - "errors" - "os" - "path/filepath" - "sync" - "syscall" -) - -var hasSymlink = sync.OnceValues(func() (bool, string) { - tmpdir, err := os.MkdirTemp("", "symtest") - if err != nil { - panic("failed to create temp directory: " + err.Error()) - } - defer os.RemoveAll(tmpdir) - - err = os.Symlink("target", filepath.Join(tmpdir, "symlink")) - switch { - case err == nil: - return true, "" - case errors.Is(err, syscall.EWINDOWS): - return false, ": symlinks are not supported on your version of Windows" - case errors.Is(err, syscall.ERROR_PRIVILEGE_NOT_HELD): - return false, ": you don't have enough privileges to create symlinks" - } - return false, "" -}) diff --git a/testing/internal/testlog/exit.go b/testing/internal/testlog/exit.go deleted file mode 100644 index b985c6b3..00000000 --- a/testing/internal/testlog/exit.go +++ /dev/null @@ -1,45 +0,0 @@ -// 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 testlog - -import ( - "sync" - _ "unsafe" // for linkname -) - -// PanicOnExit0 reports whether to panic on a call to os.Exit(0). -// This is in the testlog package because, like other definitions in -// package testlog, it is a hook between the testing package and the -// os package. This is used to ensure that an early call to os.Exit(0) -// does not cause a test to pass. -func PanicOnExit0() bool { - panicOnExit0.mu.Lock() - defer panicOnExit0.mu.Unlock() - return panicOnExit0.val -} - -// panicOnExit0 is the flag used for PanicOnExit0. This uses a lock -// because the value can be cleared via a timer call that may race -// with calls to os.Exit -var panicOnExit0 struct { - mu sync.Mutex - val bool -} - -// SetPanicOnExit0 sets panicOnExit0 to v. -// -// SetPanicOnExit0 should be an internal detail, -// but alternate implementations of go test in other -// build systems may need to access it using linkname. -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -//go:linkname SetPanicOnExit0 -func SetPanicOnExit0(v bool) { - panicOnExit0.mu.Lock() - defer panicOnExit0.mu.Unlock() - panicOnExit0.val = v -} diff --git a/testing/internal/testlog/log.go b/testing/internal/testlog/log.go deleted file mode 100644 index d8b9dcfa..00000000 --- a/testing/internal/testlog/log.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2017 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 testlog provides a back-channel communication path -// between tests and package os, so that cmd/go can see which -// environment variables and files a test consults. -package testlog - -import "sync/atomic" - -// Interface is the interface required of test loggers. -// The os package will invoke the interface's methods to indicate that -// it is inspecting the given environment variables or files. -// Multiple goroutines may call these methods simultaneously. -type Interface interface { - Getenv(key string) - Stat(file string) - Open(file string) - Chdir(dir string) -} - -// logger is the current logger Interface. -// We use an atomic.Pointer in case test startup -// is racing with goroutines started during init. -// That must not cause a race detector failure, -// although it will still result in limited visibility -// into exactly what those goroutines do. -var logger atomic.Pointer[Interface] - -// SetLogger sets the test logger implementation for the current process. -// It must be called only once, at process startup. -func SetLogger(impl Interface) { - if !logger.CompareAndSwap(nil, &impl) { - panic("testlog: SetLogger must be called only once") - } -} - -// Logger returns the current test logger implementation. -// It returns nil if there is no logger. -func Logger() Interface { - impl := logger.Load() - if impl == nil { - return nil - } - return *impl -} - -// Getenv calls Logger().Getenv, if a logger has been set. -func Getenv(name string) { - if log := Logger(); log != nil { - log.Getenv(name) - } -} - -// Open calls Logger().Open, if a logger has been set. -func Open(name string) { - if log := Logger(); log != nil { - log.Open(name) - } -} - -// Stat calls Logger().Stat, if a logger has been set. -func Stat(name string) { - if log := Logger(); log != nil { - log.Stat(name) - } -} diff --git a/testing/internal/txtar/archive.go b/testing/internal/txtar/archive.go deleted file mode 100644 index fd95f1e6..00000000 --- a/testing/internal/txtar/archive.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2018 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 txtar implements a trivial text-based file archive format. -// -// The goals for the format are: -// -// - be trivial enough to create and edit by hand. -// - be able to store trees of text files describing go command test cases. -// - diff nicely in git history and code reviews. -// -// Non-goals include being a completely general archive format, -// storing binary data, storing file modes, storing special files like -// symbolic links, and so on. -// -// # Txtar format -// -// A txtar archive is zero or more comment lines and then a sequence of file entries. -// Each file entry begins with a file marker line of the form "-- FILENAME --" -// and is followed by zero or more file content lines making up the file data. -// The comment or file content ends at the next file marker line. -// The file marker line must begin with the three-byte sequence "-- " -// and end with the three-byte sequence " --", but the enclosed -// file name can be surrounding by additional white space, -// all of which is stripped. -// -// If the txtar file is missing a trailing newline on the final line, -// parsers should consider a final newline to be present anyway. -// -// There are no possible syntax errors in a txtar archive. -package txtar - -import ( - "bytes" - "fmt" - "os" - "strings" -) - -// An Archive is a collection of files. -type Archive struct { - Comment []byte - Files []File -} - -// A File is a single file in an archive. -type File struct { - Name string // name of file ("foo/bar.txt") - Data []byte // text content of file -} - -// Format returns the serialized form of an Archive. -// It is assumed that the Archive data structure is well-formed: -// a.Comment and all a.File[i].Data contain no file marker lines, -// and all a.File[i].Name is non-empty. -func Format(a *Archive) []byte { - var buf bytes.Buffer - buf.Write(fixNL(a.Comment)) - for _, f := range a.Files { - fmt.Fprintf(&buf, "-- %s --\n", f.Name) - buf.Write(fixNL(f.Data)) - } - return buf.Bytes() -} - -// ParseFile parses the named file as an archive. -func ParseFile(file string) (*Archive, error) { - data, err := os.ReadFile(file) - if err != nil { - return nil, err - } - return Parse(data), nil -} - -// Parse parses the serialized form of an Archive. -// The returned Archive holds slices of data. -func Parse(data []byte) *Archive { - a := new(Archive) - var name string - a.Comment, name, data = findFileMarker(data) - for name != "" { - f := File{name, nil} - f.Data, name, data = findFileMarker(data) - a.Files = append(a.Files, f) - } - return a -} - -var ( - newlineMarker = []byte("\n-- ") - marker = []byte("-- ") - markerEnd = []byte(" --") -) - -// findFileMarker finds the next file marker in data, -// extracts the file name, and returns the data before the marker, -// the file name, and the data after the marker. -// If there is no next marker, findFileMarker returns before = fixNL(data), name = "", after = nil. -func findFileMarker(data []byte) (before []byte, name string, after []byte) { - var i int - for { - if name, after = isMarker(data[i:]); name != "" { - return data[:i], name, after - } - j := bytes.Index(data[i:], newlineMarker) - if j < 0 { - return fixNL(data), "", nil - } - i += j + 1 // positioned at start of new possible marker - } -} - -// isMarker checks whether data begins with a file marker line. -// If so, it returns the name from the line and the data after the line. -// Otherwise it returns name == "" with an unspecified after. -func isMarker(data []byte) (name string, after []byte) { - if !bytes.HasPrefix(data, marker) { - return "", nil - } - if i := bytes.IndexByte(data, '\n'); i >= 0 { - data, after = data[:i], data[i+1:] - } - if !(bytes.HasSuffix(data, markerEnd) && len(data) >= len(marker)+len(markerEnd)) { - return "", nil - } - return strings.TrimSpace(string(data[len(marker) : len(data)-len(markerEnd)])), after -} - -// If data is empty or ends in \n, fixNL returns data. -// Otherwise fixNL returns a new slice consisting of data with a final \n added. -func fixNL(data []byte) []byte { - if len(data) == 0 || data[len(data)-1] == '\n' { - return data - } - d := make([]byte, len(data)+1) - copy(d, data) - d[len(data)] = '\n' - return d -} diff --git a/testing/patches/benchmark.patch b/testing/patches/benchmark.patch deleted file mode 100644 index da8ce718..00000000 --- a/testing/patches/benchmark.patch +++ /dev/null @@ -1,445 +0,0 @@ -diff --git a/benchmark.go b/benchmark.go -index 882859b..668e674 100644 ---- a/benchmark.go -+++ b/benchmark.go -@@ -6,12 +6,18 @@ package testing - - import ( - "context" -+ "crypto/rand" -+ "encoding/hex" -+ "encoding/json" - "flag" - "fmt" -+ "github.com/CodSpeedHQ/codspeed-go/testing/capi" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/sysinfo" - "io" - "math" - "os" -+ "path/filepath" -+ "reflect" - "runtime" - "slices" - "strconv" -@@ -78,6 +84,17 @@ type InternalBenchmark struct { - F func(b *B) - } - -+type codspeed struct { -+ instrument_hooks *capi.InstrumentHooks -+ -+ codspeedTimePerRoundNs []time.Duration -+ codspeedItersPerRound []int64 -+ -+ startTimestamp uint64 -+ startTimestamps []uint64 -+ stopTimestamps []uint64 -+} -+ - // B is a type passed to [Benchmark] functions to manage benchmark - // timing and control the number of iterations. - // -@@ -93,6 +110,7 @@ type InternalBenchmark struct { - // affecting benchmark results. - type B struct { - common -+ codspeed - importPath string // import path of the package containing the benchmark - bstate *benchState - N int -@@ -135,28 +153,65 @@ type B struct { - // StartTimer starts timing a test. This function is called automatically - // before a benchmark starts, but it can also be used to resume timing after - // a call to [B.StopTimer]. --func (b *B) StartTimer() { -+func (b *B) StartTimerWithoutMarker() { - if !b.timerOn { -- runtime.ReadMemStats(&memStats) -- b.startAllocs = memStats.Mallocs -- b.startBytes = memStats.TotalAlloc -+ // runtime.ReadMemStats(&memStats) -+ // b.startAllocs = memStats.Mallocs -+ // b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() - b.timerOn = true -- b.loop.i &^= loopPoisonTimer -+ // b.loop.i &^= loopPoisonTimer -+ } -+} -+ -+func (b *B) StartTimer() { -+ timerOn := b.timerOn -+ -+ b.StartTimerWithoutMarker() -+ -+ if !timerOn { -+ b.startTimestamp = capi.CurrentTimestamp() - } - } - - // StopTimer stops timing a test. This can be used to pause the timer - // while performing steps that you don't want to measure. --func (b *B) StopTimer() { -+func (b *B) StopTimerWithoutMarker() { - if b.timerOn { -- b.duration += highPrecisionTimeSince(b.start) -- runtime.ReadMemStats(&memStats) -- b.netAllocs += memStats.Mallocs - b.startAllocs -- b.netBytes += memStats.TotalAlloc - b.startBytes -+ timeSinceStart := highPrecisionTimeSince(b.start) -+ b.duration += timeSinceStart -+ // runtime.ReadMemStats(&memStats) -+ // b.netAllocs += memStats.Mallocs - b.startAllocs -+ // b.netBytes += memStats.TotalAlloc - b.startBytes - b.timerOn = false - // If we hit B.Loop with the timer stopped, fail. -- b.loop.i |= loopPoisonTimer -+ // b.loop.i |= loopPoisonTimer -+ -+ // For b.N loops: This will be called in runN which sets b.N to the number of iterations. -+ // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since -+ // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as -+ // the number of iterations for this round. -+ b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) -+ b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, timeSinceStart) -+ } -+} -+ -+func (b *B) StopTimer() { -+ endTimestamp := capi.CurrentTimestamp() -+ timerOn := b.timerOn -+ -+ b.StopTimerWithoutMarker() -+ -+ if timerOn { -+ if b.startTimestamp >= endTimestamp { -+ // This should never happen, unless we have a bug in the timer logic. -+ panic(fmt.Sprintf("Invalid benchmark timestamps: start timestamp (%d) is greater than or equal to end timestamp (%d)", b.startTimestamp, endTimestamp)) -+ } -+ b.startTimestamps = append(b.startTimestamps, b.startTimestamp) -+ b.stopTimestamps = append(b.stopTimestamps, endTimestamp) -+ -+ // Reset to prevent accidental reuse -+ b.startTimestamp = 0 - } - } - -@@ -176,10 +231,29 @@ func (b *B) ResetTimer() { - b.startAllocs = memStats.Mallocs - b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() -+ -+ b.startTimestamp = capi.CurrentTimestamp() - } - b.duration = 0 - b.netAllocs = 0 - b.netBytes = 0 -+ -+ // Clear CodSpeed timestamp data -+ b.codspeedItersPerRound = b.codspeedItersPerRound[:0] -+ b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] -+ b.startTimestamps = b.startTimestamps[:0] -+ b.stopTimestamps = b.stopTimestamps[:0] -+} -+ -+func (b *B) sendAccumulatedTimestamps() { -+ for i := 0; i < len(b.startTimestamps); i++ { -+ b.instrument_hooks.AddBenchmarkTimestamps( -+ b.startTimestamps[i], -+ b.stopTimestamps[i], -+ ) -+ } -+ b.startTimestamps = b.startTimestamps[:0] -+ b.stopTimestamps = b.stopTimestamps[:0] - } - - // SetBytes records the number of bytes processed in a single operation. -@@ -195,6 +269,11 @@ func (b *B) ReportAllocs() { - - // runN runs a single benchmark for the specified number of iterations. - func (b *B) runN(n int) { -+ b.__codspeed_root_frame__runN(n) -+} -+ -+//go:noinline -+func (b *B) __codspeed_root_frame__runN(n int) { - benchmarkLock.Lock() - defer benchmarkLock.Unlock() - ctx, cancelCtx := context.WithCancel(context.Background()) -@@ -274,6 +353,8 @@ var labelsOnce sync.Once - // subbenchmarks. b must not have subbenchmarks. - func (b *B) run() { - labelsOnce.Do(func() { -+ fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") -+ - fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) - fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) - if b.importPath != "" { -@@ -344,18 +425,48 @@ func (b *B) launch() { - b.runN(b.benchTime.n) - } - } else { -- d := b.benchTime.d -- for n := int64(1); !b.failed && b.duration < d && n < 1e9; { -+ warmupD := b.benchTime.d / 10 -+ warmupN := int64(1) -+ for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { - last := n - // Predict required iterations. -- goalns := d.Nanoseconds() -+ goalns := warmupD.Nanoseconds() - prevIters := int64(b.N) - n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) - b.runN(int(n)) -+ warmupN = n -+ } -+ -+ // Reset the fields from the warmup run -+ b.ResetTimer() -+ -+ // Final run: -+ benchD := b.benchTime.d -+ benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) -+ -+ // When we have a very slow benchmark (e.g. taking 500ms), we have to: -+ // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) -+ // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds -+ const minRounds = 100 -+ var rounds int -+ var roundN int -+ if benchN < minRounds { -+ rounds = benchN -+ roundN = 1 -+ } else { -+ rounds = minRounds -+ roundN = benchN / int(rounds) - } -+ -+ b.codspeed.instrument_hooks.StartBenchmark() -+ for range rounds { -+ b.runN(int(roundN)) -+ } -+ b.codspeed.instrument_hooks.StopBenchmark() -+ b.sendAccumulatedTimestamps() - } - } -- b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.extra} -+ b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} - } - - // Elapsed returns the measured elapsed time of the benchmark. -@@ -408,9 +519,9 @@ func (b *B) stopOrScaleBLoop() bool { - - func (b *B) loopSlowPath() bool { - // Consistency checks -- if !b.timerOn { -- b.Fatal("B.Loop called with timer stopped") -- } -+ // if !b.timerOn { -+ // b.Fatal("B.Loop called with timer stopped") -+ // } - if b.loop.i&loopPoisonMask != 0 { - panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) - } -@@ -426,7 +537,9 @@ func (b *B) loopSlowPath() bool { - } - // Within a b.Loop loop, we don't use b.N (to avoid confusion). - b.N = 0 -+ b.codspeed.instrument_hooks.StartBenchmark() - b.ResetTimer() -+ b.StartTimerWithoutMarker() - - // Start the next iteration. - b.loop.i++ -@@ -448,13 +561,17 @@ func (b *B) loopSlowPath() bool { - more = b.stopOrScaleBLoop() - } - if !more { -- b.StopTimer() -+ b.StopTimerWithoutMarker() -+ b.codspeed.instrument_hooks.StopBenchmark() -+ b.sendAccumulatedTimestamps() -+ - // Commit iteration count - b.N = int(b.loop.n) - b.loop.done = true - return false - } - -+ b.StartTimerWithoutMarker() - // Start the next iteration. - b.loop.i++ - return true -@@ -495,6 +612,7 @@ func (b *B) loopSlowPath() bool { - // whereas b.N-based benchmarks must run the benchmark function (and any - // associated setup and cleanup) several times. - func (b *B) Loop() bool { -+ b.StopTimerWithoutMarker() - // This is written such that the fast path is as fast as possible and can be - // inlined. - // -@@ -509,6 +627,7 @@ func (b *B) Loop() bool { - // path can do consistency checks and fail. - if b.loop.i < b.loop.n { - b.loop.i++ -+ b.StartTimerWithoutMarker() - return true - } - return b.loopSlowPath() -@@ -535,6 +654,9 @@ type BenchmarkResult struct { - MemAllocs uint64 // The total number of memory allocations. - MemBytes uint64 // The total number of bytes allocated. - -+ CodspeedTimePerRoundNs []time.Duration -+ CodspeedItersPerRound []int64 -+ - // Extra records additional metrics reported by ReportMetric. - Extra map[string]float64 - } -@@ -715,6 +837,9 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e - w: os.Stdout, - bench: true, - }, -+ codspeed: codspeed{ -+ instrument_hooks: capi.NewInstrumentHooks(), -+ }, - importPath: importPath, - benchFunc: func(b *B) { - for _, Benchmark := range bs { -@@ -724,6 +849,8 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e - benchTime: benchTime, - bstate: bstate, - } -+ defer main.codspeed.instrument_hooks.Close() -+ - if Verbose() { - main.chatty = newChattyPrinter(main.w) - } -@@ -752,6 +879,7 @@ func (s *benchState) processBench(b *B) { - chatty: b.chatty, - bench: true, - }, -+ codspeed: b.codspeed, - benchFunc: b.benchFunc, - benchTime: b.benchTime, - } -@@ -767,6 +895,111 @@ func (s *benchState) processBench(b *B) { - continue - } - results := r.String() -+ -+ // ############################################################################################ -+ // START CODSPEED -+ type RawResults struct { -+ Name string `json:"name"` -+ Uri string `json:"uri"` -+ Pid int `json:"pid"` -+ CodspeedTimePerRoundNs []time.Duration `json:"codspeed_time_per_round_ns"` -+ CodspeedItersPerRound []int64 `json:"codspeed_iters_per_round"` -+ } -+ -+ // Find the filename of the benchmark file -+ var benchFile string -+ if b.benchFunc != nil { -+ pc := reflect.ValueOf(b.benchFunc).Pointer() -+ fn := runtime.FuncForPC(pc) -+ if fn == nil { -+ continue -+ } -+ -+ file, _ := fn.FileLine(pc) -+ if strings.HasSuffix(file, "_codspeed.go") { -+ benchFile = file -+ } -+ } -+ -+ if benchFile == "" { -+ panic("Could not determine benchmark file name") -+ } -+ -+ relativeBenchFile := getGitRelativePath(benchFile) -+ if strings.HasSuffix(relativeBenchFile, "_codspeed.go") { -+ relativeBenchFile = strings.TrimSuffix(relativeBenchFile, "_codspeed.go") + "_test.go" -+ } -+ -+ // Build custom bench name with :: separator -+ var nameParts []string -+ current := &b.common -+ for current.parent != nil { -+ // Extract the sub-benchmark part by removing parent prefix -+ parentName := current.parent.name -+ if strings.HasPrefix(current.name, parentName+"/") { -+ subName := strings.TrimPrefix(current.name, parentName+"/") -+ nameParts = append([]string{subName}, nameParts...) -+ } else { -+ nameParts = append([]string{current.name}, nameParts...) -+ } -+ -+ if current.parent.name == "Main" { -+ break -+ } -+ current = current.parent -+ } -+ benchName = strings.Join(nameParts, "::") -+ benchUri := fmt.Sprintf("%s::%s", relativeBenchFile, benchName) -+ -+ rawResults := RawResults{ -+ Name: benchName, -+ Uri: benchUri, -+ Pid: os.Getpid(), -+ CodspeedTimePerRoundNs: r.CodspeedTimePerRoundNs, -+ CodspeedItersPerRound: r.CodspeedItersPerRound, -+ } -+ -+ goRunnerMetadata, err := findGoRunnerMetadata() -+ if err != nil { -+ panic(fmt.Sprintf("failed to get go runner metadata: %v", err)) -+ } -+ -+ if err := os.MkdirAll(filepath.Join(goRunnerMetadata.ProfileFolder, "raw_results"), 0755); err != nil { -+ fmt.Fprintf(os.Stderr, "failed to create raw results directory: %v\n", err) -+ continue -+ } -+ // Generate random filename to avoid any overwrites -+ randomBytes := make([]byte, 16) -+ if _, err := rand.Read(randomBytes); err != nil { -+ fmt.Fprintf(os.Stderr, "failed to generate random filename: %v\n", err) -+ continue -+ } -+ rawResultsFile := filepath.Join(goRunnerMetadata.ProfileFolder, "raw_results", fmt.Sprintf("%s.json", hex.EncodeToString(randomBytes))) -+ file, err := os.Create(rawResultsFile) -+ if err != nil { -+ fmt.Fprintf(os.Stderr, "failed to create raw results file: %v\n", err) -+ continue -+ } -+ output, err := json.MarshalIndent(rawResults, "", " ") -+ if err != nil { -+ fmt.Fprintf(os.Stderr, "failed to marshal raw results: %v\n", err) -+ file.Close() -+ continue -+ } -+ // FIXME: Don't overwrite the file if it already exists -+ if _, err := file.Write(output); err != nil { -+ fmt.Fprintf(os.Stderr, "failed to write raw results: %v\n", err) -+ file.Close() -+ continue -+ } -+ defer file.Close() -+ -+ // Send pid and executed benchmark to the runner -+ b.codspeed.instrument_hooks.SetExecutedBenchmark(uint32(os.Getpid()), benchUri) -+ -+ // END CODSPEED -+ // ############################################################################################ -+ - if b.chatty != nil { - fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) - } -@@ -827,6 +1060,7 @@ func (b *B) Run(name string, f func(b *B)) bool { - chatty: b.chatty, - bench: true, - }, -+ codspeed: b.codspeed, - importPath: b.importPath, - benchFunc: f, - benchTime: b.benchTime, diff --git a/testing/patches/benchmark_benchmarkers_bloop.patch b/testing/patches/benchmark_benchmarkers_bloop.patch deleted file mode 100644 index 34378c10..00000000 --- a/testing/patches/benchmark_benchmarkers_bloop.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go -index 4947e11..0040973 100644 ---- a/testing/testing/benchmark.go -+++ b/testing/testing/benchmark.go -@@ -226,15 +226,7 @@ func (b *B) StopTimer() { - b.StopTimerWithoutMarker() - - if timerOn { -- if b.startTimestamp >= endTimestamp { -- // This should never happen, unless we have a bug in the timer logic. -- panic(fmt.Sprintf("Invalid benchmark timestamps: start timestamp (%d) is greater than or equal to end timestamp (%d)", b.startTimestamp, endTimestamp)) -- } -- b.startTimestamps = append(b.startTimestamps, b.startTimestamp) -- b.stopTimestamps = append(b.stopTimestamps, endTimestamp) -- -- // Reset to prevent accidental reuse -- b.startTimestamp = 0 -+ b.AddBenchmarkMarkers(endTimestamp) - } - } - -@@ -587,7 +579,18 @@ func (b *B) loopSlowPath() bool { - more = b.stopOrScaleBLoop() - } - if !more { -- b.StopTimerWithoutMarker() -+ // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function -+ // but this will result in a huge performance degradation since the C FFI calls are expensive. -+ // -+ // The only downside of having this here, is that there's a small chance of perf sampling the -+ // benchmark framework code which already happens anyway because we only emit 1 pair of -+ // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. -+ endTimestamp := capi.CurrentTimestamp() -+ -+ // Edge case: The timer is stopped in b.Loop() which prevents any further calls to -+ // StopTimer() from adding the benchmark markers. We have to manually submit them here, -+ // once the benchmark loop is done. -+ b.AddBenchmarkMarkers(endTimestamp) - b.codspeed.instrument_hooks.StopBenchmark() - b.sendAccumulatedTimestamps() diff --git a/testing/patches/benchmark_remove_codspeed_folder.patch b/testing/patches/benchmark_remove_codspeed_folder.patch deleted file mode 100644 index 43258213..00000000 --- a/testing/patches/benchmark_remove_codspeed_folder.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go -index 883976e..660c799 100644 ---- a/testing/testing/benchmark.go -+++ b/testing/testing/benchmark.go -@@ -966,6 +966,9 @@ func (s *benchState) processBench(b *B) { - relativeBenchFile := getGitRelativePath(benchFile) - if strings.HasSuffix(relativeBenchFile, "_codspeed.go") { - relativeBenchFile = strings.TrimSuffix(relativeBenchFile, "_codspeed.go") + "_test.go" -+ -+ // Remove the 'codspeed/' folder which is used for external tests -+ relativeBenchFile = removeFolderFromPath(relativeBenchFile, "codspeed") - } - - // Build custom bench name with :: separator diff --git a/testing/patches/benchmark_savemeasurement_bug.patch b/testing/patches/benchmark_savemeasurement_bug.patch deleted file mode 100644 index 7116838b..00000000 --- a/testing/patches/benchmark_savemeasurement_bug.patch +++ /dev/null @@ -1,37 +0,0 @@ -diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go -index 0040973..883976e 100644 ---- a/testing/testing/benchmark.go -+++ b/testing/testing/benchmark.go -@@ -200,6 +200,12 @@ func (b *B) SaveMeasurement() { - } - b.savedMeasurement = true - -+ // WARN: This function must not be called if the timer is on, because we -+ // would read an incomplete b.duration value. -+ if b.timerOn { -+ panic("SaveMeasurement called with timer on") -+ } -+ - // For b.N loops: This will be called in runN which sets b.N to the number of iterations. - // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since - // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as -@@ -311,8 +317,8 @@ func (b *B) __codspeed_root_frame__runN(n int) { - b.ResetTimer() - b.StartTimer() - b.benchFunc(b) -- b.SaveMeasurement() - b.StopTimer() -+ b.SaveMeasurement() - b.previousN = n - b.previousDuration = b.duration - -@@ -641,8 +647,8 @@ func (b *B) loopSlowPath() bool { - // whereas b.N-based benchmarks must run the benchmark function (and any - // associated setup and cleanup) several times. - func (b *B) Loop() bool { -- b.SaveMeasurement() - b.StopTimerWithoutMarker() -+ b.SaveMeasurement() - // This is written such that the fast path is as fast as possible and can be - // inlined. - // diff --git a/testing/patches/benchmark_stopbenchmark_fail.patch b/testing/patches/benchmark_stopbenchmark_fail.patch deleted file mode 100644 index db2357e9..00000000 --- a/testing/patches/benchmark_stopbenchmark_fail.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go -index e7e4d06..8fdea90 100644 ---- a/testing/testing/benchmark.go -+++ b/testing/testing/benchmark.go -@@ -325,6 +325,8 @@ func (b *B) run1() bool { - }() - <-b.signal - if b.failed { -+ // This case can happen with a `b.Loop()` benchmark if any of the iterations fail -+ ensureBenchmarkIsStopped(b) - fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) - return false - } -@@ -888,6 +890,8 @@ func (s *benchState) processBench(b *B) { - } - r := b.doBench() - if b.failed { -+ ensureBenchmarkIsStopped(b) -+ - // The output could be very long here, but probably isn't. - // We print it all, regardless, because we don't want to trim the reason - // the benchmark failed. diff --git a/testing/patches/benchmark_stoptimer_mitigation.patch b/testing/patches/benchmark_stoptimer_mitigation.patch deleted file mode 100644 index 5133beba..00000000 --- a/testing/patches/benchmark_stoptimer_mitigation.patch +++ /dev/null @@ -1,78 +0,0 @@ -diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go -index 8fdea90..4947e11 100644 ---- a/testing/testing/benchmark.go -+++ b/testing/testing/benchmark.go -@@ -93,6 +93,10 @@ type codspeed struct { - startTimestamp uint64 - startTimestamps []uint64 - stopTimestamps []uint64 -+ -+ // Indicates whether a measurement has been saved already. This aims to prevent saving measurements -+ // twice, because `b.Loop()` saves them internally as well but is also called from runN -+ savedMeasurement bool - } - - // B is a type passed to [Benchmark] functions to manage benchmark -@@ -160,6 +164,7 @@ func (b *B) StartTimerWithoutMarker() { - // b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() - b.timerOn = true -+ b.savedMeasurement = false - // b.loop.i &^= loopPoisonTimer - } - } -@@ -186,14 +191,32 @@ func (b *B) StopTimerWithoutMarker() { - b.timerOn = false - // If we hit B.Loop with the timer stopped, fail. - // b.loop.i |= loopPoisonTimer -+ } -+} - -- // For b.N loops: This will be called in runN which sets b.N to the number of iterations. -- // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since -- // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as -- // the number of iterations for this round. -- b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) -- b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, timeSinceStart) -+func (b *B) SaveMeasurement() { -+ if b.savedMeasurement { -+ return - } -+ b.savedMeasurement = true -+ -+ // For b.N loops: This will be called in runN which sets b.N to the number of iterations. -+ // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since -+ // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as -+ // the number of iterations for this round. -+ timeSinceStart := highPrecisionTimeSince(b.start) -+ -+ // If this gets called from b.Loop(), we have to take the duration compared to the previous StartTimer, -+ // if it's called from runN, we can use b.duration -+ duration := time.Duration(0) -+ if b.N == 0 { -+ duration = timeSinceStart -+ } else { -+ duration = b.duration -+ } -+ -+ b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) -+ b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, duration) - } - - func (b *B) StopTimer() { -@@ -296,6 +319,7 @@ func (b *B) __codspeed_root_frame__runN(n int) { - b.ResetTimer() - b.StartTimer() - b.benchFunc(b) -+ b.SaveMeasurement() - b.StopTimer() - b.previousN = n - b.previousDuration = b.duration -@@ -614,6 +638,7 @@ func (b *B) loopSlowPath() bool { - // whereas b.N-based benchmarks must run the benchmark function (and any - // associated setup and cleanup) several times. - func (b *B) Loop() bool { -+ b.SaveMeasurement() - b.StopTimerWithoutMarker() - // This is written such that the fast path is as fast as possible and can be - // inlined. diff --git a/testing/patches/internal_race.patch b/testing/patches/internal_race.patch deleted file mode 100644 index 81423006..00000000 --- a/testing/patches/internal_race.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git a/internal/race/norace.go b/internal/race/norace.go -index 8d2e5ea..49d68a4 100644 ---- a/internal/race/norace.go -+++ b/internal/race/norace.go -@@ -7,7 +7,7 @@ - package race - - import ( -- "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" -+ // "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" - "unsafe" - ) - -@@ -34,8 +34,8 @@ func Read(addr unsafe.Pointer) { - func ReadPC(addr unsafe.Pointer, callerpc, pc uintptr) { - } - --func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { --} -+// func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { -+// } - - func Write(addr unsafe.Pointer) { - } -@@ -43,8 +43,8 @@ func Write(addr unsafe.Pointer) { - func WritePC(addr unsafe.Pointer, callerpc, pc uintptr) { - } - --func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { --} -+// func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) { -+// } - - func ReadRange(addr unsafe.Pointer, len int) { - } -diff --git a/internal/race/race.go b/internal/race/race.go -index d345009..ef54ea5 100644 ---- a/internal/race/race.go -+++ b/internal/race/race.go -@@ -7,7 +7,6 @@ - package race - - import ( -- "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" - "unsafe" - ) - -@@ -36,8 +35,8 @@ func Read(addr unsafe.Pointer) - //go:linkname ReadPC - func ReadPC(addr unsafe.Pointer, callerpc, pc uintptr) - --//go:linkname ReadObjectPC --func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) -+// //go:linkname ReadObjectPC -+// func ReadObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) - - //go:linkname Write - func Write(addr unsafe.Pointer) -@@ -45,8 +44,8 @@ func Write(addr unsafe.Pointer) - //go:linkname WritePC - func WritePC(addr unsafe.Pointer, callerpc, pc uintptr) - --//go:linkname WriteObjectPC --func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) -+// //go:linkname WriteObjectPC -+// func WriteObjectPC(t *abi.Type, addr unsafe.Pointer, callerpc, pc uintptr) - - //go:linkname ReadRange - func ReadRange(addr unsafe.Pointer, len int) diff --git a/testing/patches/synctest.patch b/testing/patches/synctest.patch deleted file mode 100644 index 4a161355..00000000 --- a/testing/patches/synctest.patch +++ /dev/null @@ -1,79 +0,0 @@ -diff --git a/internal/synctest/synctest.go b/internal/synctest/synctest.go -index 69378a4..3965a9b 100644 ---- a/internal/synctest/synctest.go -+++ b/internal/synctest/synctest.go -@@ -8,7 +8,7 @@ - package synctest - - import ( -- "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" -+ // "github.com/CodSpeedHQ/codspeed-go/testing/internal/abi" - "unsafe" - ) - -@@ -32,11 +32,24 @@ const ( - OtherBubble // associated with a different bubble - ) - -+// Manual import of `Escape` to avoid the `internal/abi` dependency which contains assembly functions, which would -+// lead to linker errors due to duplicate symbols. -+var alwaysFalse bool -+var escapeSink any -+ -+// Escape forces any pointers in x to escape to the heap. -+func Escape[T any](x T) T { -+ if alwaysFalse { -+ escapeSink = x -+ } -+ return x -+} -+ - // Associate attempts to associate p with the current bubble. - // It returns the new association status of p. - func Associate[T any](p *T) Association { - // Ensure p escapes to permit us to attach a special to it. -- escapedP := abi.Escape(p) -+ escapedP := Escape(p) - return Association(associate(unsafe.Pointer(escapedP))) - } - -diff --git a/testing/synctest/synctest.go b/testing/synctest/synctest.go -index 880aa12..b0f1cd6 100644 ---- a/testing/synctest/synctest.go -+++ b/testing/synctest/synctest.go -@@ -280,7 +280,7 @@ import ( - func Test(t *testing.T, f func(*testing.T)) { - var ok bool - synctest.Run(func() { -- ok = testingSynctestTest(t, f) -+ ok = testingSynctestTest_codspeed(t, f) - }) - if !ok { - // Fail the test outside the bubble, -@@ -289,8 +289,9 @@ func Test(t *testing.T, f func(*testing.T)) { - } - } - --//go:linkname testingSynctestTest testing/synctest.testingSynctestTest --func testingSynctestTest(t *testing.T, f func(*testing.T)) bool -+// NOTE(CODSPEED): This has to be renamed because the linked has a blocklist with the exact name: https://github.com/golang/go/blob/ad3ccd92e4c2ddfc1499a5e038eb0aa0012c0dda/src/cmd/link/internal/loader/loader.go#L2469 -+//go:linkname testingSynctestTest_codspeed testing/synctest.testingSynctestTest_codspeed -+func testingSynctestTest_codspeed(t *testing.T, f func(*testing.T)) bool - - // Wait blocks until every goroutine within the current bubble, - // other than the current goroutine, is durably blocked. -diff --git a/testing/testing.go b/testing/testing.go -index c132641..1332779 100644 ---- a/testing/testing.go -+++ b/testing/testing.go -@@ -2022,8 +2022,8 @@ func (t *T) Run(name string, f func(t *T)) bool { - // testingSynctestTest runs f within a synctest bubble. - // It is called by synctest.Test, from within an already-created bubble. - // --//go:linkname testingSynctestTest testing/synctest.testingSynctestTest --func testingSynctestTest(t *T, f func(*T)) (ok bool) { -+//go:linkname testingSynctestTest_codspeed testing/synctest.testingSynctestTest_codspeed -+func testingSynctestTest_codspeed(t *T, f func(*T)) (ok bool) { - if t.cleanupStarted.Load() { - panic("testing: synctest.Run called during t.Cleanup") - } diff --git a/testing/patches/testfs.patch b/testing/patches/testfs.patch deleted file mode 100644 index 1876a979..00000000 --- a/testing/patches/testfs.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/fstest/mapfs.go b/fstest/mapfs.go -index 5ce0398..d617c4a 100644 ---- a/fstest/mapfs.go -+++ b/fstest/mapfs.go -@@ -41,7 +41,6 @@ type MapFile struct { - } - - var _ fs.FS = MapFS(nil) --var _ fs.ReadLinkFS = MapFS(nil) - var _ fs.File = (*openMapFile)(nil) - - // Open opens the named file after following any symbolic links. -diff --git a/fstest/testfs.go b/fstest/testfs.go -index 1fb84b8..ffcd91c 100644 ---- a/fstest/testfs.go -+++ b/fstest/testfs.go -@@ -449,22 +449,7 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { - } - } - -- if fsys, ok := t.fsys.(fs.ReadLinkFS); ok { -- info2, err := fsys.Lstat(path) -- if err != nil { -- t.errorf("%s: fsys.Lstat: %v", path, err) -- return -- } -- fientry2 := formatInfoEntry(info2) -- if fentry != fientry2 { -- t.errorf("%s: mismatch:\n\tentry = %s\n\tfsys.Lstat(...) = %s", path, fentry, fientry2) -- } -- feinfo := formatInfo(einfo) -- finfo2 := formatInfo(info2) -- if feinfo != finfo2 { -- t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfsys.Lstat(...) = %s\n", path, feinfo, finfo2) -- } -- } -+ t.checkReadLinkFS(path, einfo, fentry) - } - - // checkDirList checks that two directory lists contain the same files and file info. diff --git a/testing/patches/testing.patch b/testing/patches/testing.patch deleted file mode 100644 index ddf2a9a3..00000000 --- a/testing/patches/testing.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/testing.go b/testing.go -index 899f904..4d0a866 100644 ---- a/testing.go -+++ b/testing.go -@@ -811,6 +811,11 @@ func (c *common) decorate(s string, skip int) string { - } else if index := strings.LastIndexAny(file, `/\`); index >= 0 { - file = file[index+1:] - } -+ -+ // Replace _codspeed.go with _test.go for better user experience -+ if strings.HasSuffix(file, "_codspeed.go") { -+ file = strings.TrimSuffix(file, "_codspeed.go") + "_test.go" -+ } - } else { - file = "???" - } diff --git a/testing/testing/allocs.go b/testing/testing/allocs.go deleted file mode 100644 index ac005dd9..00000000 --- a/testing/testing/allocs.go +++ /dev/null @@ -1,48 +0,0 @@ -// 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 - -import ( - "runtime" -) - -// AllocsPerRun returns the average number of allocations during calls to f. -// Although the return value has type float64, it will always be an integral value. -// -// To compute the number of allocations, the function will first be run once as -// a warm-up. The average number of allocations over the specified number of -// runs will then be measured and returned. -// -// AllocsPerRun sets [runtime.GOMAXPROCS] to 1 during its measurement and will restore -// it before returning. -func AllocsPerRun(runs int, f func()) (avg float64) { - if parallelStart.Load() != parallelStop.Load() { - panic("testing: AllocsPerRun called during parallel test") - } - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) - - // Warm up the function - f() - - // Measure the starting statistics - var memstats runtime.MemStats - runtime.ReadMemStats(&memstats) - mallocs := 0 - memstats.Mallocs - - // Run the function the specified number of times - for i := 0; i < runs; i++ { - f() - } - - // Read the final statistics - runtime.ReadMemStats(&memstats) - mallocs += memstats.Mallocs - - // Average the mallocs over the runs (not counting the warm-up). - // We are forced to return a float64 because the API is silly, but do - // the division as integers so we can ask if AllocsPerRun()==1 - // instead of AllocsPerRun()<2. - return float64(mallocs / uint64(runs)) -} diff --git a/testing/testing/allocs_test.go b/testing/testing/allocs_test.go deleted file mode 100644 index bbd3ae79..00000000 --- a/testing/testing/allocs_test.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2014 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 "testing" - -var global any - -var allocsPerRunTests = []struct { - name string - fn func() - allocs float64 -}{ - {"alloc *byte", func() { global = new(*byte) }, 1}, - {"alloc complex128", func() { global = new(complex128) }, 1}, - {"alloc float64", func() { global = new(float64) }, 1}, - {"alloc int32", func() { global = new(int32) }, 1}, - {"alloc byte", func() { global = new(byte) }, 1}, -} - -func TestAllocsPerRun(t *testing.T) { - for _, tt := range allocsPerRunTests { - if allocs := testing.AllocsPerRun(100, tt.fn); allocs != tt.allocs { - t.Errorf("AllocsPerRun(100, %s) = %v, want %v", tt.name, allocs, tt.allocs) - } - } -} diff --git a/testing/testing/benchmark.go b/testing/testing/benchmark.go deleted file mode 100644 index 660c7992..00000000 --- a/testing/testing/benchmark.go +++ /dev/null @@ -1,1296 +0,0 @@ -// Copyright 2009 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 - -import ( - "context" - "crypto/rand" - "encoding/hex" - "encoding/json" - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/capi" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/sysinfo" - "io" - "math" - "os" - "path/filepath" - "reflect" - "runtime" - "slices" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - "unicode" -) - -func initBenchmarkFlags() { - matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`") - benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks") - flag.Var(&benchTime, "test.benchtime", "run each benchmark for duration `d` or N times if `d` is of the form Nx") -} - -var ( - matchBenchmarks *string - benchmarkMemory *bool - - benchTime = durationOrCountFlag{d: 1 * time.Second} // changed during test of testing package -) - -type durationOrCountFlag struct { - d time.Duration - n int - allowZero bool -} - -func (f *durationOrCountFlag) String() string { - if f.n > 0 { - return fmt.Sprintf("%dx", f.n) - } - return f.d.String() -} - -func (f *durationOrCountFlag) Set(s string) error { - if strings.HasSuffix(s, "x") { - n, err := strconv.ParseInt(s[:len(s)-1], 10, 0) - if err != nil || n < 0 || (!f.allowZero && n == 0) { - return fmt.Errorf("invalid count") - } - *f = durationOrCountFlag{n: int(n)} - return nil - } - d, err := time.ParseDuration(s) - if err != nil || d < 0 || (!f.allowZero && d == 0) { - return fmt.Errorf("invalid duration") - } - *f = durationOrCountFlag{d: d} - return nil -} - -// Global lock to ensure only one benchmark runs at a time. -var benchmarkLock sync.Mutex - -// Used for every benchmark for measuring memory. -var memStats runtime.MemStats - -// InternalBenchmark is an internal type but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -type InternalBenchmark struct { - Name string - F func(b *B) -} - -type codspeed struct { - instrument_hooks *capi.InstrumentHooks - - codspeedTimePerRoundNs []time.Duration - codspeedItersPerRound []int64 - - startTimestamp uint64 - startTimestamps []uint64 - stopTimestamps []uint64 - - // Indicates whether a measurement has been saved already. This aims to prevent saving measurements - // twice, because `b.Loop()` saves them internally as well but is also called from runN - savedMeasurement bool -} - -// B is a type passed to [Benchmark] functions to manage benchmark -// timing and control the number of iterations. -// -// A benchmark ends when its Benchmark function returns or calls any of the methods -// [B.FailNow], [B.Fatal], [B.Fatalf], [B.SkipNow], [B.Skip], or [B.Skipf]. -// Those methods must be called only from the goroutine running the Benchmark function. -// The other reporting methods, such as the variations of [B.Log] and [B.Error], -// may be called simultaneously from multiple goroutines. -// -// Like in tests, benchmark logs are accumulated during execution -// and dumped to standard output when done. Unlike in tests, benchmark logs -// are always printed, so as not to hide output whose existence may be -// affecting benchmark results. -type B struct { - common - codspeed - importPath string // import path of the package containing the benchmark - bstate *benchState - N int - previousN int // number of iterations in the previous run - previousDuration time.Duration // total duration of the previous run - benchFunc func(b *B) - benchTime durationOrCountFlag - bytes int64 - missingBytes bool // one of the subbenchmarks does not have bytes set. - timerOn bool - showAllocResult bool - result BenchmarkResult - parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines - // The initial states of memStats.Mallocs and memStats.TotalAlloc. - startAllocs uint64 - startBytes uint64 - // The net total of this test after being run. - netAllocs uint64 - netBytes uint64 - // Extra metrics collected by ReportMetric. - extra map[string]float64 - - // loop tracks the state of B.Loop - loop struct { - // n is the target number of iterations. It gets bumped up as we go. - // When the benchmark loop is done, we commit this to b.N so users can - // do reporting based on it, but we avoid exposing it until then. - n uint64 - // i is the current Loop iteration. It's strictly monotonically - // increasing toward n. - // - // The high bit is used to poison the Loop fast path and fall back to - // the slow path. - i uint64 - - done bool // set when B.Loop return false - } -} - -// StartTimer starts timing a test. This function is called automatically -// before a benchmark starts, but it can also be used to resume timing after -// a call to [B.StopTimer]. -func (b *B) StartTimerWithoutMarker() { - if !b.timerOn { - // runtime.ReadMemStats(&memStats) - // b.startAllocs = memStats.Mallocs - // b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() - b.timerOn = true - b.savedMeasurement = false - // b.loop.i &^= loopPoisonTimer - } -} - -func (b *B) StartTimer() { - timerOn := b.timerOn - - b.StartTimerWithoutMarker() - - if !timerOn { - b.startTimestamp = capi.CurrentTimestamp() - } -} - -// StopTimer stops timing a test. This can be used to pause the timer -// while performing steps that you don't want to measure. -func (b *B) StopTimerWithoutMarker() { - if b.timerOn { - timeSinceStart := highPrecisionTimeSince(b.start) - b.duration += timeSinceStart - // runtime.ReadMemStats(&memStats) - // b.netAllocs += memStats.Mallocs - b.startAllocs - // b.netBytes += memStats.TotalAlloc - b.startBytes - b.timerOn = false - // If we hit B.Loop with the timer stopped, fail. - // b.loop.i |= loopPoisonTimer - } -} - -func (b *B) SaveMeasurement() { - if b.savedMeasurement { - return - } - b.savedMeasurement = true - - // WARN: This function must not be called if the timer is on, because we - // would read an incomplete b.duration value. - if b.timerOn { - panic("SaveMeasurement called with timer on") - } - - // For b.N loops: This will be called in runN which sets b.N to the number of iterations. - // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since - // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as - // the number of iterations for this round. - timeSinceStart := highPrecisionTimeSince(b.start) - - // If this gets called from b.Loop(), we have to take the duration compared to the previous StartTimer, - // if it's called from runN, we can use b.duration - duration := time.Duration(0) - if b.N == 0 { - duration = timeSinceStart - } else { - duration = b.duration - } - - b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) - b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, duration) -} - -func (b *B) StopTimer() { - endTimestamp := capi.CurrentTimestamp() - timerOn := b.timerOn - - b.StopTimerWithoutMarker() - - if timerOn { - b.AddBenchmarkMarkers(endTimestamp) - } -} - -// ResetTimer zeroes the elapsed benchmark time and memory allocation counters -// and deletes user-reported metrics. -// It does not affect whether the timer is running. -func (b *B) ResetTimer() { - if b.extra == nil { - // Allocate the extra map before reading memory stats. - // Pre-size it to make more allocation unlikely. - b.extra = make(map[string]float64, 16) - } else { - clear(b.extra) - } - if b.timerOn { - runtime.ReadMemStats(&memStats) - b.startAllocs = memStats.Mallocs - b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() - - b.startTimestamp = capi.CurrentTimestamp() - } - b.duration = 0 - b.netAllocs = 0 - b.netBytes = 0 - - // Clear CodSpeed timestamp data - b.codspeedItersPerRound = b.codspeedItersPerRound[:0] - b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] - b.startTimestamps = b.startTimestamps[:0] - b.stopTimestamps = b.stopTimestamps[:0] -} - -func (b *B) sendAccumulatedTimestamps() { - for i := 0; i < len(b.startTimestamps); i++ { - b.instrument_hooks.AddBenchmarkTimestamps( - b.startTimestamps[i], - b.stopTimestamps[i], - ) - } - b.startTimestamps = b.startTimestamps[:0] - b.stopTimestamps = b.stopTimestamps[:0] -} - -// SetBytes records the number of bytes processed in a single operation. -// If this is called, the benchmark will report ns/op and MB/s. -func (b *B) SetBytes(n int64) { b.bytes = n } - -// ReportAllocs enables malloc statistics for this benchmark. -// It is equivalent to setting -test.benchmem, but it only affects the -// benchmark function that calls ReportAllocs. -func (b *B) ReportAllocs() { - b.showAllocResult = true -} - -// runN runs a single benchmark for the specified number of iterations. -func (b *B) runN(n int) { - b.__codspeed_root_frame__runN(n) -} - -//go:noinline -func (b *B) __codspeed_root_frame__runN(n int) { - benchmarkLock.Lock() - defer benchmarkLock.Unlock() - ctx, cancelCtx := context.WithCancel(context.Background()) - defer func() { - b.runCleanup(normalPanic) - b.checkRaces() - }() - // Try to get a comparable environment for each run - // by clearing garbage from previous runs. - runtime.GC() - b.resetRaces() - b.N = n - b.loop.n = 0 - b.loop.i = 0 - b.loop.done = false - b.ctx = ctx - b.cancelCtx = cancelCtx - - b.parallelism = 1 - b.ResetTimer() - b.StartTimer() - b.benchFunc(b) - b.StopTimer() - b.SaveMeasurement() - b.previousN = n - b.previousDuration = b.duration - - if b.loop.n > 0 && !b.loop.done && !b.failed { - b.Error("benchmark function returned without B.Loop() == false (break or return in loop?)") - } -} - -// run1 runs the first iteration of benchFunc. It reports whether more -// iterations of this benchmarks should be run. -func (b *B) run1() bool { - if bstate := b.bstate; bstate != nil { - // Extend maxLen, if needed. - if n := len(b.name) + bstate.extLen + 1; n > bstate.maxLen { - bstate.maxLen = n + 8 // Add additional slack to avoid too many jumps in size. - } - } - go func() { - // Signal that we're done whether we return normally - // or by FailNow's runtime.Goexit. - defer func() { - b.signal <- true - }() - - b.runN(1) - }() - <-b.signal - if b.failed { - // This case can happen with a `b.Loop()` benchmark if any of the iterations fail - ensureBenchmarkIsStopped(b) - fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) - return false - } - // Only print the output if we know we are not going to proceed. - // Otherwise it is printed in processBench. - b.mu.RLock() - finished := b.finished - b.mu.RUnlock() - if b.hasSub.Load() || finished { - tag := "BENCH" - if b.skipped { - tag = "SKIP" - } - if b.chatty != nil && (len(b.output) > 0 || finished) { - b.trimOutput() - fmt.Fprintf(b.w, "%s--- %s: %s\n%s", b.chatty.prefix(), tag, b.name, b.output) - } - return false - } - return true -} - -var labelsOnce sync.Once - -// run executes the benchmark in a separate goroutine, including all of its -// subbenchmarks. b must not have subbenchmarks. -func (b *B) run() { - labelsOnce.Do(func() { - fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") - - fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) - fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) - if b.importPath != "" { - fmt.Fprintf(b.w, "pkg: %s\n", b.importPath) - } - if cpu := sysinfo.CPUName(); cpu != "" { - fmt.Fprintf(b.w, "cpu: %s\n", cpu) - } - }) - if b.bstate != nil { - // Running go test --test.bench - b.bstate.processBench(b) // Must call doBench. - } else { - // Running func Benchmark. - b.doBench() - } -} - -func (b *B) doBench() BenchmarkResult { - go b.launch() - <-b.signal - return b.result -} - -func predictN(goalns int64, prevIters int64, prevns int64, last int64) int { - if prevns == 0 { - // Round up to dodge divide by zero. See https://go.dev/issue/70709. - prevns = 1 - } - - // Order of operations matters. - // For very fast benchmarks, prevIters ~= prevns. - // If you divide first, you get 0 or 1, - // which can hide an order of magnitude in execution time. - // So multiply first, then divide. - n := goalns * prevIters / prevns - // Run more iterations than we think we'll need (1.2x). - n += n / 5 - // Don't grow too fast in case we had timing errors previously. - n = min(n, 100*last) - // Be sure to run at least one more than last time. - n = max(n, last+1) - // Don't run more than 1e9 times. (This also keeps n in int range on 32 bit platforms.) - n = min(n, 1e9) - return int(n) -} - -// launch launches the benchmark function. It gradually increases the number -// of benchmark iterations until the benchmark runs for the requested benchtime. -// launch is run by the doBench function as a separate goroutine. -// run1 must have been called on b. -func (b *B) launch() { - // Signal that we're done whether we return normally - // or by FailNow's runtime.Goexit. - defer func() { - b.signal <- true - }() - - // b.Loop does its own ramp-up logic so we just need to run it once. - // If b.loop.n is non zero, it means b.Loop has already run. - if b.loop.n == 0 { - // Run the benchmark for at least the specified amount of time. - if b.benchTime.n > 0 { - // We already ran a single iteration in run1. - // If -benchtime=1x was requested, use that result. - // See https://golang.org/issue/32051. - if b.benchTime.n > 1 { - b.runN(b.benchTime.n) - } - } else { - warmupD := b.benchTime.d / 10 - warmupN := int64(1) - for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { - last := n - // Predict required iterations. - goalns := warmupD.Nanoseconds() - prevIters := int64(b.N) - n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) - b.runN(int(n)) - warmupN = n - } - - // Reset the fields from the warmup run - b.ResetTimer() - - // Final run: - benchD := b.benchTime.d - benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) - - // When we have a very slow benchmark (e.g. taking 500ms), we have to: - // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) - // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds - const minRounds = 100 - var rounds int - var roundN int - if benchN < minRounds { - rounds = benchN - roundN = 1 - } else { - rounds = minRounds - roundN = benchN / int(rounds) - } - - b.codspeed.instrument_hooks.StartBenchmark() - for range rounds { - b.runN(int(roundN)) - } - b.codspeed.instrument_hooks.StopBenchmark() - b.sendAccumulatedTimestamps() - } - } - b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} -} - -// Elapsed returns the measured elapsed time of the benchmark. -// The duration reported by Elapsed matches the one measured by -// [B.StartTimer], [B.StopTimer], and [B.ResetTimer]. -func (b *B) Elapsed() time.Duration { - d := b.duration - if b.timerOn { - d += highPrecisionTimeSince(b.start) - } - return d -} - -// ReportMetric adds "n unit" to the reported benchmark results. -// If the metric is per-iteration, the caller should divide by b.N, -// and by convention units should end in "/op". -// ReportMetric overrides any previously reported value for the same unit. -// ReportMetric panics if unit is the empty string or if unit contains -// any whitespace. -// If unit is a unit normally reported by the benchmark framework itself -// (such as "allocs/op"), ReportMetric will override that metric. -// Setting "ns/op" to 0 will suppress that built-in metric. -func (b *B) ReportMetric(n float64, unit string) { - if unit == "" { - panic("metric unit must not be empty") - } - if strings.IndexFunc(unit, unicode.IsSpace) >= 0 { - panic("metric unit must not contain whitespace") - } - b.extra[unit] = n -} - -func (b *B) stopOrScaleBLoop() bool { - t := b.Elapsed() - if t >= b.benchTime.d { - // We've reached the target - return false - } - // Loop scaling - goalns := b.benchTime.d.Nanoseconds() - prevIters := int64(b.loop.n) - b.loop.n = uint64(predictN(goalns, prevIters, t.Nanoseconds(), prevIters)) - if b.loop.n&loopPoisonMask != 0 { - // The iteration count should never get this high, but if it did we'd be - // in big trouble. - panic("loop iteration target overflow") - } - return true -} - -func (b *B) loopSlowPath() bool { - // Consistency checks - // if !b.timerOn { - // b.Fatal("B.Loop called with timer stopped") - // } - if b.loop.i&loopPoisonMask != 0 { - panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) - } - - if b.loop.n == 0 { - // It's the first call to b.Loop() in the benchmark function. - if b.benchTime.n > 0 { - // Fixed iteration count. - b.loop.n = uint64(b.benchTime.n) - } else { - // Initialize target to 1 to kick start loop scaling. - b.loop.n = 1 - } - // Within a b.Loop loop, we don't use b.N (to avoid confusion). - b.N = 0 - b.codspeed.instrument_hooks.StartBenchmark() - b.ResetTimer() - b.StartTimerWithoutMarker() - - // Start the next iteration. - b.loop.i++ - return true - } - - // Should we keep iterating? - var more bool - if b.benchTime.n > 0 { - // The iteration count is fixed, so we should have run this many and now - // be done. - if b.loop.i != uint64(b.benchTime.n) { - // We shouldn't be able to reach the slow path in this case. - panic(fmt.Sprintf("iteration count %d < fixed target %d", b.loop.i, b.benchTime.n)) - } - more = false - } else { - // Handle fixed time case - more = b.stopOrScaleBLoop() - } - if !more { - // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function - // but this will result in a huge performance degradation since the C FFI calls are expensive. - // - // The only downside of having this here, is that there's a small chance of perf sampling the - // benchmark framework code which already happens anyway because we only emit 1 pair of - // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. - endTimestamp := capi.CurrentTimestamp() - - // Edge case: The timer is stopped in b.Loop() which prevents any further calls to - // StopTimer() from adding the benchmark markers. We have to manually submit them here, - // once the benchmark loop is done. - b.AddBenchmarkMarkers(endTimestamp) - b.codspeed.instrument_hooks.StopBenchmark() - b.sendAccumulatedTimestamps() - - // Commit iteration count - b.N = int(b.loop.n) - b.loop.done = true - return false - } - - b.StartTimerWithoutMarker() - // Start the next iteration. - b.loop.i++ - return true -} - -// Loop returns true as long as the benchmark should continue running. -// -// A typical benchmark is structured like: -// -// func Benchmark(b *testing.B) { -// ... setup ... -// for b.Loop() { -// ... code to measure ... -// } -// ... cleanup ... -// } -// -// Loop resets the benchmark timer the first time it is called in a benchmark, -// so any setup performed prior to starting the benchmark loop does not count -// toward the benchmark measurement. Likewise, when it returns false, it stops -// the timer so cleanup code is not measured. -// -// Within the body of a "for b.Loop() { ... }" loop, arguments to and -// results from function calls within the loop are kept alive, preventing -// the compiler from fully optimizing away the loop body. Currently, this is -// implemented by disabling inlining of functions called in a b.Loop loop. -// This applies only to calls syntactically between the curly braces of the loop, -// and the loop condition must be written exactly as "b.Loop()". Optimizations -// are performed as usual in any functions called by the loop. -// -// After Loop returns false, b.N contains the total number of iterations that -// ran, so the benchmark may use b.N to compute other average metrics. -// -// Prior to the introduction of Loop, benchmarks were expected to contain an -// explicit loop from 0 to b.N. Benchmarks should either use Loop or contain a -// loop to b.N, but not both. Loop offers more automatic management of the -// benchmark timer, and runs each benchmark function only once per measurement, -// whereas b.N-based benchmarks must run the benchmark function (and any -// associated setup and cleanup) several times. -func (b *B) Loop() bool { - b.StopTimerWithoutMarker() - b.SaveMeasurement() - // This is written such that the fast path is as fast as possible and can be - // inlined. - // - // There are three cases where we'll fall out of the fast path: - // - // - On the first call, both i and n are 0. - // - // - If the loop reaches the n'th iteration, then i == n and we need - // to figure out the new target iteration count or if we're done. - // - // - If the timer is stopped, it poisons the top bit of i so the slow - // path can do consistency checks and fail. - if b.loop.i < b.loop.n { - b.loop.i++ - b.StartTimerWithoutMarker() - return true - } - return b.loopSlowPath() -} - -// The loopPoison constants can be OR'd into B.loop.i to cause it to fall back -// to the slow path. -const ( - loopPoisonTimer = uint64(1 << (63 - iota)) - // If necessary, add more poison bits here. - - // loopPoisonMask is the set of all loop poison bits. (iota-1) is the index - // of the bit we just set, from which we recreate that bit mask. We subtract - // 1 to set all of the bits below that bit, then complement the result to - // get the mask. Sorry, not sorry. - loopPoisonMask = ^uint64((1 << (63 - (iota - 1))) - 1) -) - -// BenchmarkResult contains the results of a benchmark run. -type BenchmarkResult struct { - N int // The number of iterations. - T time.Duration // The total time taken. - Bytes int64 // Bytes processed in one iteration. - MemAllocs uint64 // The total number of memory allocations. - MemBytes uint64 // The total number of bytes allocated. - - CodspeedTimePerRoundNs []time.Duration - CodspeedItersPerRound []int64 - - // Extra records additional metrics reported by ReportMetric. - Extra map[string]float64 -} - -// NsPerOp returns the "ns/op" metric. -func (r BenchmarkResult) NsPerOp() int64 { - if v, ok := r.Extra["ns/op"]; ok { - return int64(v) - } - if r.N <= 0 { - return 0 - } - return r.T.Nanoseconds() / int64(r.N) -} - -// mbPerSec returns the "MB/s" metric. -func (r BenchmarkResult) mbPerSec() float64 { - if v, ok := r.Extra["MB/s"]; ok { - return v - } - if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { - return 0 - } - return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() -} - -// AllocsPerOp returns the "allocs/op" metric, -// which is calculated as r.MemAllocs / r.N. -func (r BenchmarkResult) AllocsPerOp() int64 { - if v, ok := r.Extra["allocs/op"]; ok { - return int64(v) - } - if r.N <= 0 { - return 0 - } - return int64(r.MemAllocs) / int64(r.N) -} - -// AllocedBytesPerOp returns the "B/op" metric, -// which is calculated as r.MemBytes / r.N. -func (r BenchmarkResult) AllocedBytesPerOp() int64 { - if v, ok := r.Extra["B/op"]; ok { - return int64(v) - } - if r.N <= 0 { - return 0 - } - return int64(r.MemBytes) / int64(r.N) -} - -// String returns a summary of the benchmark results. -// It follows the benchmark result line format from -// https://golang.org/design/14313-benchmark-format, not including the -// benchmark name. -// Extra metrics override built-in metrics of the same name. -// String does not include allocs/op or B/op, since those are reported -// by [BenchmarkResult.MemString]. -func (r BenchmarkResult) String() string { - buf := new(strings.Builder) - fmt.Fprintf(buf, "%8d", r.N) - - // Get ns/op as a float. - ns, ok := r.Extra["ns/op"] - if !ok { - ns = float64(r.T.Nanoseconds()) / float64(r.N) - } - if ns != 0 { - buf.WriteByte('\t') - prettyPrint(buf, ns, "ns/op") - } - - if mbs := r.mbPerSec(); mbs != 0 { - fmt.Fprintf(buf, "\t%7.2f MB/s", mbs) - } - - // Print extra metrics that aren't represented in the standard - // metrics. - var extraKeys []string - for k := range r.Extra { - switch k { - case "ns/op", "MB/s", "B/op", "allocs/op": - // Built-in metrics reported elsewhere. - continue - } - extraKeys = append(extraKeys, k) - } - slices.Sort(extraKeys) - for _, k := range extraKeys { - buf.WriteByte('\t') - prettyPrint(buf, r.Extra[k], k) - } - return buf.String() -} - -func prettyPrint(w io.Writer, x float64, unit string) { - // Print all numbers with 10 places before the decimal point - // and small numbers with four sig figs. Field widths are - // chosen to fit the whole part in 10 places while aligning - // the decimal point of all fractional formats. - var format string - switch y := math.Abs(x); { - case y == 0 || y >= 999.95: - format = "%10.0f %s" - case y >= 99.995: - format = "%12.1f %s" - case y >= 9.9995: - format = "%13.2f %s" - case y >= 0.99995: - format = "%14.3f %s" - case y >= 0.099995: - format = "%15.4f %s" - case y >= 0.0099995: - format = "%16.5f %s" - case y >= 0.00099995: - format = "%17.6f %s" - default: - format = "%18.7f %s" - } - fmt.Fprintf(w, format, x, unit) -} - -// MemString returns r.AllocedBytesPerOp and r.AllocsPerOp in the same format as 'go test'. -func (r BenchmarkResult) MemString() string { - return fmt.Sprintf("%8d B/op\t%8d allocs/op", - r.AllocedBytesPerOp(), r.AllocsPerOp()) -} - -// benchmarkName returns full name of benchmark including procs suffix. -func benchmarkName(name string, n int) string { - if n != 1 { - return fmt.Sprintf("%s-%d", name, n) - } - return name -} - -type benchState struct { - match *matcher - - maxLen int // The largest recorded benchmark name. - extLen int // Maximum extension length. -} - -// RunBenchmarks is an internal function but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { - runBenchmarks("", matchString, benchmarks) -} - -func runBenchmarks(importPath string, matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool { - // If no flag was specified, don't run benchmarks. - if len(*matchBenchmarks) == 0 { - return true - } - // Collect matching benchmarks and determine longest name. - maxprocs := 1 - for _, procs := range cpuList { - if procs > maxprocs { - maxprocs = procs - } - } - bstate := &benchState{ - match: newMatcher(matchString, *matchBenchmarks, "-test.bench", *skip), - extLen: len(benchmarkName("", maxprocs)), - } - var bs []InternalBenchmark - for _, Benchmark := range benchmarks { - if _, matched, _ := bstate.match.fullName(nil, Benchmark.Name); matched { - bs = append(bs, Benchmark) - benchName := benchmarkName(Benchmark.Name, maxprocs) - if l := len(benchName) + bstate.extLen + 1; l > bstate.maxLen { - bstate.maxLen = l - } - } - } - main := &B{ - common: common{ - name: "Main", - w: os.Stdout, - bench: true, - }, - codspeed: codspeed{ - instrument_hooks: capi.NewInstrumentHooks(), - }, - importPath: importPath, - benchFunc: func(b *B) { - for _, Benchmark := range bs { - b.Run(Benchmark.Name, Benchmark.F) - } - }, - benchTime: benchTime, - bstate: bstate, - } - defer main.codspeed.instrument_hooks.Close() - - if Verbose() { - main.chatty = newChattyPrinter(main.w) - } - main.runN(1) - return !main.failed -} - -// processBench runs bench b for the configured CPU counts and prints the results. -func (s *benchState) processBench(b *B) { - for i, procs := range cpuList { - for j := uint(0); j < *count; j++ { - runtime.GOMAXPROCS(procs) - benchName := benchmarkName(b.name, procs) - - // If it's chatty, we've already printed this information. - if b.chatty == nil { - fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) - } - // Recompute the running time for all but the first iteration. - if i > 0 || j > 0 { - b = &B{ - common: common{ - signal: make(chan bool), - name: b.name, - w: b.w, - chatty: b.chatty, - bench: true, - }, - codspeed: b.codspeed, - benchFunc: b.benchFunc, - benchTime: b.benchTime, - } - b.setOutputWriter() - b.run1() - } - r := b.doBench() - if b.failed { - ensureBenchmarkIsStopped(b) - - // The output could be very long here, but probably isn't. - // We print it all, regardless, because we don't want to trim the reason - // the benchmark failed. - fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), benchName, b.output) - continue - } - results := r.String() - - // ############################################################################################ - // START CODSPEED - type RawResults struct { - Name string `json:"name"` - Uri string `json:"uri"` - Pid int `json:"pid"` - CodspeedTimePerRoundNs []time.Duration `json:"codspeed_time_per_round_ns"` - CodspeedItersPerRound []int64 `json:"codspeed_iters_per_round"` - } - - // Find the filename of the benchmark file - var benchFile string - if b.benchFunc != nil { - pc := reflect.ValueOf(b.benchFunc).Pointer() - fn := runtime.FuncForPC(pc) - if fn == nil { - continue - } - - file, _ := fn.FileLine(pc) - if strings.HasSuffix(file, "_codspeed.go") { - benchFile = file - } - } - - if benchFile == "" { - panic("Could not determine benchmark file name") - } - - relativeBenchFile := getGitRelativePath(benchFile) - if strings.HasSuffix(relativeBenchFile, "_codspeed.go") { - relativeBenchFile = strings.TrimSuffix(relativeBenchFile, "_codspeed.go") + "_test.go" - - // Remove the 'codspeed/' folder which is used for external tests - relativeBenchFile = removeFolderFromPath(relativeBenchFile, "codspeed") - } - - // Build custom bench name with :: separator - var nameParts []string - current := &b.common - for current.parent != nil { - // Extract the sub-benchmark part by removing parent prefix - parentName := current.parent.name - if strings.HasPrefix(current.name, parentName+"/") { - subName := strings.TrimPrefix(current.name, parentName+"/") - nameParts = append([]string{subName}, nameParts...) - } else { - nameParts = append([]string{current.name}, nameParts...) - } - - if current.parent.name == "Main" { - break - } - current = current.parent - } - benchName = strings.Join(nameParts, "::") - benchUri := fmt.Sprintf("%s::%s", relativeBenchFile, benchName) - - rawResults := RawResults{ - Name: benchName, - Uri: benchUri, - Pid: os.Getpid(), - CodspeedTimePerRoundNs: r.CodspeedTimePerRoundNs, - CodspeedItersPerRound: r.CodspeedItersPerRound, - } - - goRunnerMetadata, err := findGoRunnerMetadata() - if err != nil { - panic(fmt.Sprintf("failed to get go runner metadata: %v", err)) - } - - if err := os.MkdirAll(filepath.Join(goRunnerMetadata.ProfileFolder, "raw_results"), 0755); err != nil { - fmt.Fprintf(os.Stderr, "failed to create raw results directory: %v\n", err) - continue - } - // Generate random filename to avoid any overwrites - randomBytes := make([]byte, 16) - if _, err := rand.Read(randomBytes); err != nil { - fmt.Fprintf(os.Stderr, "failed to generate random filename: %v\n", err) - continue - } - rawResultsFile := filepath.Join(goRunnerMetadata.ProfileFolder, "raw_results", fmt.Sprintf("%s.json", hex.EncodeToString(randomBytes))) - file, err := os.Create(rawResultsFile) - if err != nil { - fmt.Fprintf(os.Stderr, "failed to create raw results file: %v\n", err) - continue - } - output, err := json.MarshalIndent(rawResults, "", " ") - if err != nil { - fmt.Fprintf(os.Stderr, "failed to marshal raw results: %v\n", err) - file.Close() - continue - } - // FIXME: Don't overwrite the file if it already exists - if _, err := file.Write(output); err != nil { - fmt.Fprintf(os.Stderr, "failed to write raw results: %v\n", err) - file.Close() - continue - } - defer file.Close() - - // Send pid and executed benchmark to the runner - b.codspeed.instrument_hooks.SetExecutedBenchmark(uint32(os.Getpid()), benchUri) - - // END CODSPEED - // ############################################################################################ - - if b.chatty != nil { - fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) - } - if *benchmarkMemory || b.showAllocResult { - results += "\t" + r.MemString() - } - fmt.Fprintln(b.w, results) - // Unlike with tests, we ignore the -chatty flag and always print output for - // benchmarks since the output generation time will skew the results. - if len(b.output) > 0 { - b.trimOutput() - fmt.Fprintf(b.w, "%s--- BENCH: %s\n%s", b.chatty.prefix(), benchName, b.output) - } - if p := runtime.GOMAXPROCS(-1); p != procs { - fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) - } - if b.chatty != nil && b.chatty.json { - b.chatty.Updatef("", "=== NAME %s\n", "") - } - } - } -} - -// If hideStdoutForTesting is true, Run does not print the benchName. -// This avoids a spurious print during 'go test' on package testing itself, -// which invokes b.Run in its own tests (see sub_test.go). -var hideStdoutForTesting = false - -// Run benchmarks f as a subbenchmark with the given name. It reports -// whether there were any failures. -// -// A subbenchmark is like any other benchmark. A benchmark that calls Run at -// least once will not be measured itself and will be called once with N=1. -func (b *B) Run(name string, f func(b *B)) bool { - // Since b has subbenchmarks, we will no longer run it as a benchmark itself. - // Release the lock and acquire it on exit to ensure locks stay paired. - b.hasSub.Store(true) - benchmarkLock.Unlock() - defer benchmarkLock.Lock() - - benchName, ok, partial := b.name, true, false - if b.bstate != nil { - benchName, ok, partial = b.bstate.match.fullName(&b.common, name) - } - if !ok { - return true - } - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - sub := &B{ - common: common{ - signal: make(chan bool), - name: benchName, - parent: &b.common, - level: b.level + 1, - creator: pc[:n], - w: b.w, - chatty: b.chatty, - bench: true, - }, - codspeed: b.codspeed, - importPath: b.importPath, - benchFunc: f, - benchTime: b.benchTime, - bstate: b.bstate, - } - sub.setOutputWriter() - if partial { - // Partial name match, like -bench=X/Y matching BenchmarkX. - // Only process sub-benchmarks, if any. - sub.hasSub.Store(true) - } - - if b.chatty != nil { - labelsOnce.Do(func() { - fmt.Printf("goos: %s\n", runtime.GOOS) - fmt.Printf("goarch: %s\n", runtime.GOARCH) - if b.importPath != "" { - fmt.Printf("pkg: %s\n", b.importPath) - } - if cpu := sysinfo.CPUName(); cpu != "" { - fmt.Printf("cpu: %s\n", cpu) - } - }) - - if !hideStdoutForTesting { - if b.chatty.json { - b.chatty.Updatef(benchName, "=== RUN %s\n", benchName) - } - fmt.Println(benchName) - } - } - - if sub.run1() { - sub.run() - } - b.add(sub.result) - return !sub.failed -} - -// add simulates running benchmarks in sequence in a single iteration. It is -// used to give some meaningful results in case func Benchmark is used in -// combination with Run. -func (b *B) add(other BenchmarkResult) { - r := &b.result - // The aggregated BenchmarkResults resemble running all subbenchmarks as - // in sequence in a single benchmark. - r.N = 1 - r.T += time.Duration(other.NsPerOp()) - if other.Bytes == 0 { - // Summing Bytes is meaningless in aggregate if not all subbenchmarks - // set it. - b.missingBytes = true - r.Bytes = 0 - } - if !b.missingBytes { - r.Bytes += other.Bytes - } - r.MemAllocs += uint64(other.AllocsPerOp()) - r.MemBytes += uint64(other.AllocedBytesPerOp()) -} - -// trimOutput shortens the output from a benchmark, which can be very long. -func (b *B) trimOutput() { - // The output is likely to appear multiple times because the benchmark - // is run multiple times, but at least it will be seen. This is not a big deal - // because benchmarks rarely print, but just in case, we trim it if it's too long. - const maxNewlines = 10 - for nlCount, j := 0, 0; j < len(b.output); j++ { - if b.output[j] == '\n' { - nlCount++ - if nlCount >= maxNewlines { - b.output = append(b.output[:j], "\n\t... [output truncated]\n"...) - break - } - } - } -} - -// A PB is used by RunParallel for running parallel benchmarks. -type PB struct { - globalN *atomic.Uint64 // shared between all worker goroutines iteration counter - grain uint64 // acquire that many iterations from globalN at once - cache uint64 // local cache of acquired iterations - bN uint64 // total number of iterations to execute (b.N) -} - -// Next reports whether there are more iterations to execute. -func (pb *PB) Next() bool { - if pb.cache == 0 { - n := pb.globalN.Add(pb.grain) - if n <= pb.bN { - pb.cache = pb.grain - } else if n < pb.bN+pb.grain { - pb.cache = pb.bN + pb.grain - n - } else { - return false - } - } - pb.cache-- - return true -} - -// RunParallel runs a benchmark in parallel. -// It creates multiple goroutines and distributes b.N iterations among them. -// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for -// non-CPU-bound benchmarks, call [B.SetParallelism] before RunParallel. -// RunParallel is usually used with the go test -cpu flag. -// -// The body function will be run in each goroutine. It should set up any -// goroutine-local state and then iterate until pb.Next returns false. -// It should not use the [B.StartTimer], [B.StopTimer], or [B.ResetTimer] functions, -// because they have global effect. It should also not call [B.Run]. -// -// RunParallel reports ns/op values as wall time for the benchmark as a whole, -// not the sum of wall time or CPU time over each parallel goroutine. -func (b *B) RunParallel(body func(*PB)) { - if b.N == 0 { - return // Nothing to do when probing. - } - // Calculate grain size as number of iterations that take ~100µs. - // 100µs is enough to amortize the overhead and provide sufficient - // dynamic load balancing. - grain := uint64(0) - if b.previousN > 0 && b.previousDuration > 0 { - grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration) - } - if grain < 1 { - grain = 1 - } - // We expect the inner loop and function call to take at least 10ns, - // so do not do more than 100µs/10ns=1e4 iterations. - if grain > 1e4 { - grain = 1e4 - } - - var n atomic.Uint64 - numProcs := b.parallelism * runtime.GOMAXPROCS(0) - var wg sync.WaitGroup - wg.Add(numProcs) - for p := 0; p < numProcs; p++ { - go func() { - defer wg.Done() - pb := &PB{ - globalN: &n, - grain: grain, - bN: uint64(b.N), - } - body(pb) - }() - } - wg.Wait() - if n.Load() <= uint64(b.N) && !b.Failed() { - b.Fatal("RunParallel: body exited without pb.Next() == false") - } -} - -// SetParallelism sets the number of goroutines used by [B.RunParallel] to p*GOMAXPROCS. -// There is usually no need to call SetParallelism for CPU-bound benchmarks. -// If p is less than 1, this call will have no effect. -func (b *B) SetParallelism(p int) { - if p >= 1 { - b.parallelism = p - } -} - -// Benchmark benchmarks a single function. It is useful for creating -// custom benchmarks that do not use the "go test" command. -// -// If f depends on testing flags, then [Init] must be used to register -// those flags before calling Benchmark and before calling [flag.Parse]. -// -// If f calls Run, the result will be an estimate of running all its -// subbenchmarks that don't call Run in sequence in a single benchmark. -func Benchmark(f func(b *B)) BenchmarkResult { - b := &B{ - common: common{ - signal: make(chan bool), - w: discard{}, - }, - benchFunc: f, - benchTime: benchTime, - } - b.setOutputWriter() - if b.run1() { - b.run() - } - return b.result -} - -type discard struct{} - -func (discard) Write(b []byte) (n int, err error) { return len(b), nil } diff --git a/testing/testing/benchmark_test.go b/testing/testing/benchmark_test.go deleted file mode 100644 index e2dd24c8..00000000 --- a/testing/testing/benchmark_test.go +++ /dev/null @@ -1,244 +0,0 @@ -// 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" - "context" - "errors" - "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 TestBenchmarkContext(t *testing.T) { - testing.Benchmark(func(b *testing.B) { - ctx := b.Context() - if err := ctx.Err(); err != nil { - b.Fatalf("expected non-canceled context, got %v", err) - } - - var innerCtx context.Context - b.Run("inner", func(b *testing.B) { - innerCtx = b.Context() - if err := innerCtx.Err(); err != nil { - b.Fatalf("expected inner benchmark to not inherit canceled context, got %v", err) - } - }) - b.Run("inner2", func(b *testing.B) { - if !errors.Is(innerCtx.Err(), context.Canceled) { - t.Fatal("expected context of sibling benchmark to be canceled after its test function finished") - } - }) - - t.Cleanup(func() { - if !errors.Is(ctx.Err(), context.Canceled) { - t.Fatal("expected context canceled before cleanup") - } - }) - }) -} - -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 b.Loop() { - 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") - }) -} diff --git a/testing/testing/codspeed.go b/testing/testing/codspeed.go deleted file mode 100644 index d4db60d8..00000000 --- a/testing/testing/codspeed.go +++ /dev/null @@ -1,103 +0,0 @@ -package testing - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" -) - -type GoRunnerMetadata struct { - ProfileFolder string `json:"profile_folder"` - RelativePackagePath string `json:"relative_package_path"` -} - -func findGoRunnerMetadata() (*GoRunnerMetadata, error) { - cwd, err := os.Getwd() - if err != nil { - return nil, err - } - - // Search up the directory tree for go-runner.metadata - currentDir := cwd - for { - metadataPath := filepath.Join(currentDir, "go-runner.metadata") - data, err := os.ReadFile(metadataPath) - if err == nil { - var metadata GoRunnerMetadata - err = json.Unmarshal(data, &metadata) - if err != nil { - return nil, err - } - return &metadata, nil - } - - parentDir := filepath.Dir(currentDir) - if parentDir == currentDir { - // Reached the root directory - break - } - currentDir = parentDir - } - - return nil, os.ErrNotExist -} - -func getGitRelativePath(absPath string) string { - canonicalizedAbsPath, err := filepath.EvalSymlinks(absPath) - if err != nil { - panic(fmt.Sprintf("failed to evaluate symlinks for path %s: %v", absPath, err)) - } - - cwd, err := os.Getwd() - if err != nil { - panic(fmt.Sprintf("failed to get current working directory: %v", err)) - } - - cwdRelativePath, err := filepath.Rel(cwd, canonicalizedAbsPath) - if err != nil { - panic(fmt.Sprintf("failed to compute relative path from %s to %s: %v", cwd, canonicalizedAbsPath, err)) - } - - goRunnerMetadata, err := findGoRunnerMetadata() - if err != nil { - panic(fmt.Sprintf("failed to find go-runner metadata: %v", err)) - } - - return filepath.Join(goRunnerMetadata.RelativePackagePath, cwdRelativePath) -} - -// If the benchmark execution failed, we have to ensure to stop the benchmark, which -// will send the event to the runner to also stop perf. Otherwise we could possibly -// sample a lot of data that isn't relevant. Additionally, we want to ensure that -// the emitted markers are correct (otherwise we'd have a SampleStart without a SampleStop). -func ensureBenchmarkIsStopped(b *B) { - b.codspeed.instrument_hooks.StopBenchmark() -} - -func (b *B) AddBenchmarkMarkers(endTimestamp uint64) { - if b.startTimestamp >= endTimestamp { - // This should never happen, unless we have a bug in the timer logic. - panic(fmt.Sprintf("Invalid benchmark timestamps: start timestamp (%d) is greater than or equal to end timestamp (%d)", b.startTimestamp, endTimestamp)) - } - - b.startTimestamps = append(b.startTimestamps, b.startTimestamp) - b.stopTimestamps = append(b.stopTimestamps, endTimestamp) - - // Reset to prevent accidental reuse - b.startTimestamp = 0 -} - -func removeFolderFromPath(path string, folder string) string { - parts := strings.Split(path, string(os.PathSeparator)) - - var newParts []string - for _, p := range parts { - if p != folder { - newParts = append(newParts, p) - } - } - - return filepath.Join(newParts...) -} diff --git a/testing/testing/cover.go b/testing/testing/cover.go deleted file mode 100644 index 74c97d47..00000000 --- a/testing/testing/cover.go +++ /dev/null @@ -1,37 +0,0 @@ -// 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. - -// Support for test coverage. - -package testing - -// CoverBlock records the coverage data for a single basic block. -// The fields are 1-indexed, as in an editor: The opening line of -// the file is number 1, for example. Columns are measured -// in bytes. -// NOTE: This struct is internal to the testing infrastructure and may change. -// It is not covered (yet) by the Go 1 compatibility guidelines. -type CoverBlock struct { - Line0 uint32 // Line number for block start. - Col0 uint16 // Column number for block start. - Line1 uint32 // Line number for block end. - Col1 uint16 // Column number for block end. - Stmts uint16 // Number of statements included in this block. -} - -// Cover records information about test coverage checking. -// NOTE: This struct is internal to the testing infrastructure and may change. -// It is not covered (yet) by the Go 1 compatibility guidelines. -type Cover struct { - Mode string - Counters map[string][]uint32 - Blocks map[string][]CoverBlock - CoveredPackages string -} - -// RegisterCover records the coverage data accumulators for the tests. -// NOTE: This function is internal to the testing infrastructure and may change. -// It is not covered (yet) by the Go 1 compatibility guidelines. -func RegisterCover(c Cover) { -} diff --git a/testing/testing/example.go b/testing/testing/example.go deleted file mode 100644 index 58c36f2e..00000000 --- a/testing/testing/example.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2009 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 - -import ( - "fmt" - "runtime" - "slices" - "strings" - "time" -) - -type InternalExample struct { - Name string - F func() - Output string - Unordered bool -} - -// RunExamples is an internal function but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) { - _, ok = runExamples(matchString, examples) - return ok -} - -func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) { - ok = true - - m := newMatcher(matchString, *match, "-test.run", *skip) - - var eg InternalExample - for _, eg = range examples { - _, matched, _ := m.fullName(nil, eg.Name) - if !matched { - continue - } - ran = true - if !runExample(eg) { - ok = false - } - } - - return ran, ok -} - -// processRunResult computes a summary and status of the result of running an example test. -// stdout is the captured output from stdout of the test. -// recovered is the result of invoking recover after running the test, in case it panicked. -// -// If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout. -// If the test is chatty/verbose, it'll print a success message to stdout. -// If recovered is non-nil, it'll panic with that value. -// If the test panicked with nil, or invoked runtime.Goexit, it'll be -// made to fail and panic with errNilPanicOrGoexit -func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered any) (passed bool) { - passed = true - dstr := fmtDuration(timeSpent) - var fail string - got := strings.TrimSpace(stdout) - want := strings.TrimSpace(eg.Output) - if runtime.GOOS == "windows" { - got = strings.ReplaceAll(got, "\r\n", "\n") - want = strings.ReplaceAll(want, "\r\n", "\n") - } - if eg.Unordered { - gotLines := slices.Sorted(strings.SplitSeq(got, "\n")) - wantLines := slices.Sorted(strings.SplitSeq(want, "\n")) - if !slices.Equal(gotLines, wantLines) && recovered == nil { - fail = fmt.Sprintf("got:\n%s\nwant (unordered):\n%s\n", stdout, eg.Output) - } - } else { - if got != want && recovered == nil { - fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want) - } - } - if fail != "" || !finished || recovered != nil { - fmt.Printf("%s--- FAIL: %s (%s)\n%s", chatty.prefix(), eg.Name, dstr, fail) - passed = false - } else if chatty.on { - fmt.Printf("%s--- PASS: %s (%s)\n", chatty.prefix(), eg.Name, dstr) - } - - if chatty.on && chatty.json { - fmt.Printf("%s=== NAME %s\n", chatty.prefix(), "") - } - - if recovered != nil { - // Propagate the previously recovered result, by panicking. - panic(recovered) - } else if !finished { - panic(errNilPanicOrGoexit) - } - - return -} diff --git a/testing/testing/example_loop_test.go b/testing/testing/example_loop_test.go deleted file mode 100644 index eff8bab3..00000000 --- a/testing/testing/example_loop_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 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 ( - "math/rand/v2" - "testing" -) - -// ExBenchmark shows how to use b.Loop in a benchmark. -// -// (If this were a real benchmark, not an example, this would be named -// BenchmarkSomething.) -func ExBenchmark(b *testing.B) { - // Generate a large random slice to use as an input. - // Since this is done before the first call to b.Loop(), - // it doesn't count toward the benchmark time. - input := make([]int, 128<<10) - for i := range input { - input[i] = rand.Int() - } - - // Perform the benchmark. - for b.Loop() { - // Normally, the compiler would be allowed to optimize away the call - // to sum because it has no side effects and the result isn't used. - // However, inside a b.Loop loop, the compiler ensures function calls - // aren't optimized away. - sum(input) - } - - // Outside the loop, the timer is stopped, so we could perform - // cleanup if necessary without affecting the result. -} - -func sum(data []int) int { - total := 0 - for _, value := range data { - total += value - } - return total -} - -func ExampleB_Loop() { - testing.Benchmark(ExBenchmark) -} diff --git a/testing/testing/export_test.go b/testing/testing/export_test.go deleted file mode 100644 index a2dddc79..00000000 --- a/testing/testing/export_test.go +++ /dev/null @@ -1,13 +0,0 @@ -// 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 - -var PrettyPrint = prettyPrint - -type HighPrecisionTime = highPrecisionTime - -var HighPrecisionTimeNow = highPrecisionTimeNow - -const ParallelConflict = parallelConflict diff --git a/testing/testing/flag_test.go b/testing/testing/flag_test.go deleted file mode 100644 index 89e4a65b..00000000 --- a/testing/testing/flag_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2022 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 ( - "flag" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "testing" -) - -var testFlagArg = flag.String("test_flag_arg", "", "TestFlag: passing -v option") - -const flagTestEnv = "GO_WANT_FLAG_HELPER_PROCESS" - -func TestFlag(t *testing.T) { - if os.Getenv(flagTestEnv) == "1" { - testFlagHelper(t) - return - } - - testenv.MustHaveExec(t) - - for _, flag := range []string{"", "-test.v", "-test.v=test2json"} { - flag := flag - t.Run(flag, func(t *testing.T) { - t.Parallel() - cmd := exec.Command(testenv.Executable(t), "-test.run=^TestFlag$", "-test_flag_arg="+flag) - if flag != "" { - cmd.Args = append(cmd.Args, flag) - } - cmd.Env = append(cmd.Environ(), flagTestEnv+"=1") - b, err := cmd.CombinedOutput() - if len(b) > 0 { - // When we set -test.v=test2json, we need to escape the ^V control - // character used for JSON framing so that the JSON parser doesn't - // misinterpret the subprocess output as output from the parent test. - t.Logf("%q", b) - } - if err != nil { - t.Error(err) - } - }) - } -} - -// testFlagHelper is called by the TestFlagHelper subprocess. -func testFlagHelper(t *testing.T) { - f := flag.Lookup("test.v") - if f == nil { - t.Fatal(`flag.Lookup("test.v") failed`) - } - - bf, ok := f.Value.(interface{ IsBoolFlag() bool }) - if !ok { - t.Errorf("test.v flag (type %T) does not have IsBoolFlag method", f) - } else if !bf.IsBoolFlag() { - t.Error("test.v IsBoolFlag() returned false") - } - - gf, ok := f.Value.(flag.Getter) - if !ok { - t.Fatalf("test.v flag (type %T) does not have Get method", f) - } - v := gf.Get() - - var want any - switch *testFlagArg { - case "": - want = false - case "-test.v": - want = true - case "-test.v=test2json": - want = "test2json" - default: - t.Fatalf("unexpected test_flag_arg %q", *testFlagArg) - } - - if v != want { - t.Errorf("test.v is %v want %v", v, want) - } -} diff --git a/testing/testing/fstest/mapfs.go b/testing/testing/fstest/mapfs.go deleted file mode 100644 index d617c4a9..00000000 --- a/testing/testing/fstest/mapfs.go +++ /dev/null @@ -1,340 +0,0 @@ -// 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 fstest - -import ( - "io" - "io/fs" - "path" - "slices" - "strings" - "time" -) - -// A MapFS is a simple in-memory file system for use in tests, -// represented as a map from path names (arguments to Open) -// to information about the files, directories, or symbolic links they represent. -// -// The map need not include parent directories for files contained -// in the map; those will be synthesized if needed. -// But a directory can still be included by setting the [MapFile.Mode]'s [fs.ModeDir] bit; -// this may be necessary for detailed control over the directory's [fs.FileInfo] -// or to create an empty directory. -// -// File system operations read directly from the map, -// so that the file system can be changed by editing the map as needed. -// An implication is that file system operations must not run concurrently -// with changes to the map, which would be a race. -// Another implication is that opening or reading a directory requires -// iterating over the entire map, so a MapFS should typically be used with not more -// than a few hundred entries or directory reads. -type MapFS map[string]*MapFile - -// A MapFile describes a single file in a [MapFS]. -type MapFile struct { - Data []byte // file content or symlink destination - Mode fs.FileMode // fs.FileInfo.Mode - ModTime time.Time // fs.FileInfo.ModTime - Sys any // fs.FileInfo.Sys -} - -var _ fs.FS = MapFS(nil) -var _ fs.File = (*openMapFile)(nil) - -// Open opens the named file after following any symbolic links. -func (fsys MapFS) Open(name string) (fs.File, error) { - if !fs.ValidPath(name) { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} - } - realName, ok := fsys.resolveSymlinks(name) - if !ok { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} - } - - file := fsys[realName] - if file != nil && file.Mode&fs.ModeDir == 0 { - // Ordinary file - return &openMapFile{name, mapFileInfo{path.Base(name), file}, 0}, nil - } - - // Directory, possibly synthesized. - // Note that file can be nil here: the map need not contain explicit parent directories for all its files. - // But file can also be non-nil, in case the user wants to set metadata for the directory explicitly. - // Either way, we need to construct the list of children of this directory. - var list []mapFileInfo - var need = make(map[string]bool) - if realName == "." { - for fname, f := range fsys { - i := strings.Index(fname, "/") - if i < 0 { - if fname != "." { - list = append(list, mapFileInfo{fname, f}) - } - } else { - need[fname[:i]] = true - } - } - } else { - prefix := realName + "/" - for fname, f := range fsys { - if strings.HasPrefix(fname, prefix) { - felem := fname[len(prefix):] - i := strings.Index(felem, "/") - if i < 0 { - list = append(list, mapFileInfo{felem, f}) - } else { - need[fname[len(prefix):len(prefix)+i]] = true - } - } - } - // If the directory name is not in the map, - // and there are no children of the name in the map, - // then the directory is treated as not existing. - if file == nil && list == nil && len(need) == 0 { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist} - } - } - for _, fi := range list { - delete(need, fi.name) - } - for name := range need { - list = append(list, mapFileInfo{name, &MapFile{Mode: fs.ModeDir | 0555}}) - } - slices.SortFunc(list, func(a, b mapFileInfo) int { - return strings.Compare(a.name, b.name) - }) - - if file == nil { - file = &MapFile{Mode: fs.ModeDir | 0555} - } - var elem string - if name == "." { - elem = "." - } else { - elem = name[strings.LastIndex(name, "/")+1:] - } - return &mapDir{name, mapFileInfo{elem, file}, list, 0}, nil -} - -func (fsys MapFS) resolveSymlinks(name string) (_ string, ok bool) { - // Fast path: if a symlink is in the map, resolve it. - if file := fsys[name]; file != nil && file.Mode.Type() == fs.ModeSymlink { - target := string(file.Data) - if path.IsAbs(target) { - return "", false - } - return fsys.resolveSymlinks(path.Join(path.Dir(name), target)) - } - - // Check if each parent directory (starting at root) is a symlink. - for i := 0; i < len(name); { - j := strings.Index(name[i:], "/") - var dir string - if j < 0 { - dir = name - i = len(name) - } else { - dir = name[:i+j] - i += j - } - if file := fsys[dir]; file != nil && file.Mode.Type() == fs.ModeSymlink { - target := string(file.Data) - if path.IsAbs(target) { - return "", false - } - return fsys.resolveSymlinks(path.Join(path.Dir(dir), target) + name[i:]) - } - i += len("/") - } - return name, fs.ValidPath(name) -} - -// ReadLink returns the destination of the named symbolic link. -func (fsys MapFS) ReadLink(name string) (string, error) { - info, err := fsys.lstat(name) - if err != nil { - return "", &fs.PathError{Op: "readlink", Path: name, Err: err} - } - if info.f.Mode.Type() != fs.ModeSymlink { - return "", &fs.PathError{Op: "readlink", Path: name, Err: fs.ErrInvalid} - } - return string(info.f.Data), nil -} - -// Lstat returns a FileInfo describing the named file. -// If the file is a symbolic link, the returned FileInfo describes the symbolic link. -// Lstat makes no attempt to follow the link. -func (fsys MapFS) Lstat(name string) (fs.FileInfo, error) { - info, err := fsys.lstat(name) - if err != nil { - return nil, &fs.PathError{Op: "lstat", Path: name, Err: err} - } - return info, nil -} - -func (fsys MapFS) lstat(name string) (*mapFileInfo, error) { - if !fs.ValidPath(name) { - return nil, fs.ErrNotExist - } - realDir, ok := fsys.resolveSymlinks(path.Dir(name)) - if !ok { - return nil, fs.ErrNotExist - } - elem := path.Base(name) - realName := path.Join(realDir, elem) - - file := fsys[realName] - if file != nil { - return &mapFileInfo{elem, file}, nil - } - - if realName == "." { - return &mapFileInfo{elem, &MapFile{Mode: fs.ModeDir | 0555}}, nil - } - // Maybe a directory. - prefix := realName + "/" - for fname := range fsys { - if strings.HasPrefix(fname, prefix) { - return &mapFileInfo{elem, &MapFile{Mode: fs.ModeDir | 0555}}, nil - } - } - // If the directory name is not in the map, - // and there are no children of the name in the map, - // then the directory is treated as not existing. - return nil, fs.ErrNotExist -} - -// fsOnly is a wrapper that hides all but the fs.FS methods, -// to avoid an infinite recursion when implementing special -// methods in terms of helpers that would use them. -// (In general, implementing these methods using the package fs helpers -// is redundant and unnecessary, but having the methods may make -// MapFS exercise more code paths when used in tests.) -type fsOnly struct{ fs.FS } - -func (fsys MapFS) ReadFile(name string) ([]byte, error) { - return fs.ReadFile(fsOnly{fsys}, name) -} - -func (fsys MapFS) Stat(name string) (fs.FileInfo, error) { - return fs.Stat(fsOnly{fsys}, name) -} - -func (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error) { - return fs.ReadDir(fsOnly{fsys}, name) -} - -func (fsys MapFS) Glob(pattern string) ([]string, error) { - return fs.Glob(fsOnly{fsys}, pattern) -} - -type noSub struct { - MapFS -} - -func (noSub) Sub() {} // not the fs.SubFS signature - -func (fsys MapFS) Sub(dir string) (fs.FS, error) { - return fs.Sub(noSub{fsys}, dir) -} - -// A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. -type mapFileInfo struct { - name string - f *MapFile -} - -func (i *mapFileInfo) Name() string { return path.Base(i.name) } -func (i *mapFileInfo) Size() int64 { return int64(len(i.f.Data)) } -func (i *mapFileInfo) Mode() fs.FileMode { return i.f.Mode } -func (i *mapFileInfo) Type() fs.FileMode { return i.f.Mode.Type() } -func (i *mapFileInfo) ModTime() time.Time { return i.f.ModTime } -func (i *mapFileInfo) IsDir() bool { return i.f.Mode&fs.ModeDir != 0 } -func (i *mapFileInfo) Sys() any { return i.f.Sys } -func (i *mapFileInfo) Info() (fs.FileInfo, error) { return i, nil } - -func (i *mapFileInfo) String() string { - return fs.FormatFileInfo(i) -} - -// An openMapFile is a regular (non-directory) fs.File open for reading. -type openMapFile struct { - path string - mapFileInfo - offset int64 -} - -func (f *openMapFile) Stat() (fs.FileInfo, error) { return &f.mapFileInfo, nil } - -func (f *openMapFile) Close() error { return nil } - -func (f *openMapFile) Read(b []byte) (int, error) { - if f.offset >= int64(len(f.f.Data)) { - return 0, io.EOF - } - if f.offset < 0 { - return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid} - } - n := copy(b, f.f.Data[f.offset:]) - f.offset += int64(n) - return n, nil -} - -func (f *openMapFile) Seek(offset int64, whence int) (int64, error) { - switch whence { - case 0: - // offset += 0 - case 1: - offset += f.offset - case 2: - offset += int64(len(f.f.Data)) - } - if offset < 0 || offset > int64(len(f.f.Data)) { - return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid} - } - f.offset = offset - return offset, nil -} - -func (f *openMapFile) ReadAt(b []byte, offset int64) (int, error) { - if offset < 0 || offset > int64(len(f.f.Data)) { - return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid} - } - n := copy(b, f.f.Data[offset:]) - if n < len(b) { - return n, io.EOF - } - return n, nil -} - -// A mapDir is a directory fs.File (so also an fs.ReadDirFile) open for reading. -type mapDir struct { - path string - mapFileInfo - entry []mapFileInfo - offset int -} - -func (d *mapDir) Stat() (fs.FileInfo, error) { return &d.mapFileInfo, nil } -func (d *mapDir) Close() error { return nil } -func (d *mapDir) Read(b []byte) (int, error) { - return 0, &fs.PathError{Op: "read", Path: d.path, Err: fs.ErrInvalid} -} - -func (d *mapDir) ReadDir(count int) ([]fs.DirEntry, error) { - n := len(d.entry) - d.offset - if n == 0 && count > 0 { - return nil, io.EOF - } - if count > 0 && n > count { - n = count - } - list := make([]fs.DirEntry, n) - for i := range list { - list[i] = &d.entry[d.offset+i] - } - d.offset += n - return list, nil -} diff --git a/testing/testing/fstest/mapfs_test.go b/testing/testing/fstest/mapfs_test.go deleted file mode 100644 index e7ff4180..00000000 --- a/testing/testing/fstest/mapfs_test.go +++ /dev/null @@ -1,125 +0,0 @@ -// 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 fstest - -import ( - "fmt" - "io/fs" - "strings" - "testing" -) - -func TestMapFS(t *testing.T) { - m := MapFS{ - "hello": {Data: []byte("hello, world\n")}, - "fortune/k/ken.txt": {Data: []byte("If a program is too slow, it must have a loop.\n")}, - } - if err := TestFS(m, "hello", "fortune", "fortune/k", "fortune/k/ken.txt"); err != nil { - t.Fatal(err) - } -} - -func TestMapFSChmodDot(t *testing.T) { - m := MapFS{ - "a/b.txt": &MapFile{Mode: 0666}, - ".": &MapFile{Mode: 0777 | fs.ModeDir}, - } - buf := new(strings.Builder) - fs.WalkDir(m, ".", func(path string, d fs.DirEntry, err error) error { - fi, err := d.Info() - if err != nil { - return err - } - fmt.Fprintf(buf, "%s: %v\n", path, fi.Mode()) - return nil - }) - want := ` -.: drwxrwxrwx -a: dr-xr-xr-x -a/b.txt: -rw-rw-rw- -`[1:] - got := buf.String() - if want != got { - t.Errorf("MapFS modes want:\n%s\ngot:\n%s\n", want, got) - } -} - -func TestMapFSFileInfoName(t *testing.T) { - m := MapFS{ - "path/to/b.txt": &MapFile{}, - } - info, _ := m.Stat("path/to/b.txt") - want := "b.txt" - got := info.Name() - if want != got { - t.Errorf("MapFS FileInfo.Name want:\n%s\ngot:\n%s\n", want, got) - } -} - -func TestMapFSSymlink(t *testing.T) { - const fileContent = "If a program is too slow, it must have a loop.\n" - m := MapFS{ - "fortune/k/ken.txt": {Data: []byte(fileContent)}, - "dirlink": {Data: []byte("fortune/k"), Mode: fs.ModeSymlink}, - "linklink": {Data: []byte("dirlink"), Mode: fs.ModeSymlink}, - "ken.txt": {Data: []byte("dirlink/ken.txt"), Mode: fs.ModeSymlink}, - } - if err := TestFS(m, "fortune/k/ken.txt", "dirlink", "ken.txt", "linklink"); err != nil { - t.Error(err) - } - - gotData, err := fs.ReadFile(m, "ken.txt") - if string(gotData) != fileContent || err != nil { - t.Errorf("fs.ReadFile(m, \"ken.txt\") = %q, %v; want %q, ", gotData, err, fileContent) - } - gotLink, err := fs.ReadLink(m, "dirlink") - if want := "fortune/k"; gotLink != want || err != nil { - t.Errorf("fs.ReadLink(m, \"dirlink\") = %q, %v; want %q, ", gotLink, err, fileContent) - } - gotInfo, err := fs.Lstat(m, "dirlink") - if err != nil { - t.Errorf("fs.Lstat(m, \"dirlink\") = _, %v; want _, ", err) - } else { - if got, want := gotInfo.Name(), "dirlink"; got != want { - t.Errorf("fs.Lstat(m, \"dirlink\").Name() = %q; want %q", got, want) - } - if got, want := gotInfo.Mode(), fs.ModeSymlink; got != want { - t.Errorf("fs.Lstat(m, \"dirlink\").Mode() = %v; want %v", got, want) - } - } - gotInfo, err = fs.Stat(m, "dirlink") - if err != nil { - t.Errorf("fs.Stat(m, \"dirlink\") = _, %v; want _, ", err) - } else { - if got, want := gotInfo.Name(), "dirlink"; got != want { - t.Errorf("fs.Stat(m, \"dirlink\").Name() = %q; want %q", got, want) - } - if got, want := gotInfo.Mode(), fs.ModeDir|0555; got != want { - t.Errorf("fs.Stat(m, \"dirlink\").Mode() = %v; want %v", got, want) - } - } - gotInfo, err = fs.Lstat(m, "linklink") - if err != nil { - t.Errorf("fs.Lstat(m, \"linklink\") = _, %v; want _, ", err) - } else { - if got, want := gotInfo.Name(), "linklink"; got != want { - t.Errorf("fs.Lstat(m, \"linklink\").Name() = %q; want %q", got, want) - } - if got, want := gotInfo.Mode(), fs.ModeSymlink; got != want { - t.Errorf("fs.Lstat(m, \"linklink\").Mode() = %v; want %v", got, want) - } - } - gotInfo, err = fs.Stat(m, "linklink") - if err != nil { - t.Errorf("fs.Stat(m, \"linklink\") = _, %v; want _, ", err) - } else { - if got, want := gotInfo.Name(), "linklink"; got != want { - t.Errorf("fs.Stat(m, \"linklink\").Name() = %q; want %q", got, want) - } - if got, want := gotInfo.Mode(), fs.ModeDir|0555; got != want { - t.Errorf("fs.Stat(m, \"linklink\").Mode() = %v; want %v", got, want) - } - } -} diff --git a/testing/testing/fstest/testfs.go b/testing/testing/fstest/testfs.go deleted file mode 100644 index ffcd91c7..00000000 --- a/testing/testing/fstest/testfs.go +++ /dev/null @@ -1,625 +0,0 @@ -// 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 fstest implements support for testing implementations and users of file systems. -package fstest - -import ( - "errors" - "fmt" - "io" - "io/fs" - "maps" - "path" - "slices" - "strings" - "testing/iotest" -) - -// TestFS tests a file system implementation. -// It walks the entire tree of files in fsys, -// opening and checking that each file behaves correctly. -// Symbolic links are not followed, -// but their Lstat values are checked -// if the file system implements [fs.ReadLinkFS]. -// It also checks that the file system contains at least the expected files. -// As a special case, if no expected files are listed, fsys must be empty. -// Otherwise, fsys must contain at least the listed files; it can also contain others. -// The contents of fsys must not change concurrently with TestFS. -// -// If TestFS finds any misbehaviors, it returns either the first error or a -// list of errors. Use [errors.Is] or [errors.As] to inspect. -// -// Typical usage inside a test is: -// -// if err := fstest.TestFS(myFS, "file/that/should/be/present"); err != nil { -// t.Fatal(err) -// } -func TestFS(fsys fs.FS, expected ...string) error { - if err := testFS(fsys, expected...); err != nil { - return err - } - for _, name := range expected { - if i := strings.Index(name, "/"); i >= 0 { - dir, dirSlash := name[:i], name[:i+1] - var subExpected []string - for _, name := range expected { - if strings.HasPrefix(name, dirSlash) { - subExpected = append(subExpected, name[len(dirSlash):]) - } - } - sub, err := fs.Sub(fsys, dir) - if err != nil { - return err - } - if err := testFS(sub, subExpected...); err != nil { - return fmt.Errorf("testing fs.Sub(fsys, %s): %w", dir, err) - } - break // one sub-test is enough - } - } - return nil -} - -func testFS(fsys fs.FS, expected ...string) error { - t := fsTester{fsys: fsys} - t.checkDir(".") - t.checkOpen(".") - found := make(map[string]bool) - for _, dir := range t.dirs { - found[dir] = true - } - for _, file := range t.files { - found[file] = true - } - delete(found, ".") - if len(expected) == 0 && len(found) > 0 { - list := slices.Sorted(maps.Keys(found)) - if len(list) > 15 { - list = append(list[:10], "...") - } - t.errorf("expected empty file system but found files:\n%s", strings.Join(list, "\n")) - } - for _, name := range expected { - if !found[name] { - t.errorf("expected but not found: %s", name) - } - } - if len(t.errors) == 0 { - return nil - } - return fmt.Errorf("TestFS found errors:\n%w", errors.Join(t.errors...)) -} - -// An fsTester holds state for running the test. -type fsTester struct { - fsys fs.FS - errors []error - dirs []string - files []string -} - -// errorf adds an error to the list of errors. -func (t *fsTester) errorf(format string, args ...any) { - t.errors = append(t.errors, fmt.Errorf(format, args...)) -} - -func (t *fsTester) openDir(dir string) fs.ReadDirFile { - f, err := t.fsys.Open(dir) - if err != nil { - t.errorf("%s: Open: %w", dir, err) - return nil - } - d, ok := f.(fs.ReadDirFile) - if !ok { - f.Close() - t.errorf("%s: Open returned File type %T, not a fs.ReadDirFile", dir, f) - return nil - } - return d -} - -// checkDir checks the directory dir, which is expected to exist -// (it is either the root or was found in a directory listing with IsDir true). -func (t *fsTester) checkDir(dir string) { - // Read entire directory. - t.dirs = append(t.dirs, dir) - d := t.openDir(dir) - if d == nil { - return - } - list, err := d.ReadDir(-1) - if err != nil { - d.Close() - t.errorf("%s: ReadDir(-1): %w", dir, err) - return - } - - // Check all children. - var prefix string - if dir == "." { - prefix = "" - } else { - prefix = dir + "/" - } - for _, info := range list { - name := info.Name() - switch { - case name == ".", name == "..", name == "": - t.errorf("%s: ReadDir: child has invalid name: %#q", dir, name) - continue - case strings.Contains(name, "/"): - t.errorf("%s: ReadDir: child name contains slash: %#q", dir, name) - continue - case strings.Contains(name, `\`): - t.errorf("%s: ReadDir: child name contains backslash: %#q", dir, name) - continue - } - path := prefix + name - t.checkStat(path, info) - t.checkOpen(path) - switch info.Type() { - case fs.ModeDir: - t.checkDir(path) - case fs.ModeSymlink: - // No further processing. - // Avoid following symlinks to avoid potentially unbounded recursion. - t.files = append(t.files, path) - default: - t.checkFile(path) - } - } - - // Check ReadDir(-1) at EOF. - list2, err := d.ReadDir(-1) - if len(list2) > 0 || err != nil { - d.Close() - t.errorf("%s: ReadDir(-1) at EOF = %d entries, %w, wanted 0 entries, nil", dir, len(list2), err) - return - } - - // Check ReadDir(1) at EOF (different results). - list2, err = d.ReadDir(1) - if len(list2) > 0 || err != io.EOF { - d.Close() - t.errorf("%s: ReadDir(1) at EOF = %d entries, %w, wanted 0 entries, EOF", dir, len(list2), err) - return - } - - // Check that close does not report an error. - if err := d.Close(); err != nil { - t.errorf("%s: Close: %w", dir, err) - } - - // Check that closing twice doesn't crash. - // The return value doesn't matter. - d.Close() - - // Reopen directory, read a second time, make sure contents match. - if d = t.openDir(dir); d == nil { - return - } - defer d.Close() - list2, err = d.ReadDir(-1) - if err != nil { - t.errorf("%s: second Open+ReadDir(-1): %w", dir, err) - return - } - t.checkDirList(dir, "first Open+ReadDir(-1) vs second Open+ReadDir(-1)", list, list2) - - // Reopen directory, read a third time in pieces, make sure contents match. - if d = t.openDir(dir); d == nil { - return - } - defer d.Close() - list2 = nil - for { - n := 1 - if len(list2) > 0 { - n = 2 - } - frag, err := d.ReadDir(n) - if len(frag) > n { - t.errorf("%s: third Open: ReadDir(%d) after %d: %d entries (too many)", dir, n, len(list2), len(frag)) - return - } - list2 = append(list2, frag...) - if err == io.EOF { - break - } - if err != nil { - t.errorf("%s: third Open: ReadDir(%d) after %d: %w", dir, n, len(list2), err) - return - } - if n == 0 { - t.errorf("%s: third Open: ReadDir(%d) after %d: 0 entries but nil error", dir, n, len(list2)) - return - } - } - t.checkDirList(dir, "first Open+ReadDir(-1) vs third Open+ReadDir(1,2) loop", list, list2) - - // If fsys has ReadDir, check that it matches and is sorted. - if fsys, ok := t.fsys.(fs.ReadDirFS); ok { - list2, err := fsys.ReadDir(dir) - if err != nil { - t.errorf("%s: fsys.ReadDir: %w", dir, err) - return - } - t.checkDirList(dir, "first Open+ReadDir(-1) vs fsys.ReadDir", list, list2) - - for i := 0; i+1 < len(list2); i++ { - if list2[i].Name() >= list2[i+1].Name() { - t.errorf("%s: fsys.ReadDir: list not sorted: %s before %s", dir, list2[i].Name(), list2[i+1].Name()) - } - } - } - - // Check fs.ReadDir as well. - list2, err = fs.ReadDir(t.fsys, dir) - if err != nil { - t.errorf("%s: fs.ReadDir: %w", dir, err) - return - } - t.checkDirList(dir, "first Open+ReadDir(-1) vs fs.ReadDir", list, list2) - - for i := 0; i+1 < len(list2); i++ { - if list2[i].Name() >= list2[i+1].Name() { - t.errorf("%s: fs.ReadDir: list not sorted: %s before %s", dir, list2[i].Name(), list2[i+1].Name()) - } - } - - t.checkGlob(dir, list2) -} - -// formatEntry formats an fs.DirEntry into a string for error messages and comparison. -func formatEntry(entry fs.DirEntry) string { - return fmt.Sprintf("%s IsDir=%v Type=%v", entry.Name(), entry.IsDir(), entry.Type()) -} - -// formatInfoEntry formats an fs.FileInfo into a string like the result of formatEntry, for error messages and comparison. -func formatInfoEntry(info fs.FileInfo) string { - return fmt.Sprintf("%s IsDir=%v Type=%v", info.Name(), info.IsDir(), info.Mode().Type()) -} - -// formatInfo formats an fs.FileInfo into a string for error messages and comparison. -func formatInfo(info fs.FileInfo) string { - return fmt.Sprintf("%s IsDir=%v Mode=%v Size=%d ModTime=%v", info.Name(), info.IsDir(), info.Mode(), info.Size(), info.ModTime()) -} - -// checkGlob checks that various glob patterns work if the file system implements GlobFS. -func (t *fsTester) checkGlob(dir string, list []fs.DirEntry) { - if _, ok := t.fsys.(fs.GlobFS); !ok { - return - } - - // Make a complex glob pattern prefix that only matches dir. - var glob string - if dir != "." { - elem := strings.Split(dir, "/") - for i, e := range elem { - var pattern []rune - for j, r := range e { - if r == '*' || r == '?' || r == '\\' || r == '[' || r == '-' { - pattern = append(pattern, '\\', r) - continue - } - switch (i + j) % 5 { - case 0: - pattern = append(pattern, r) - case 1: - pattern = append(pattern, '[', r, ']') - case 2: - pattern = append(pattern, '[', r, '-', r, ']') - case 3: - pattern = append(pattern, '[', '\\', r, ']') - case 4: - pattern = append(pattern, '[', '\\', r, '-', '\\', r, ']') - } - } - elem[i] = string(pattern) - } - glob = strings.Join(elem, "/") + "/" - } - - // Test that malformed patterns are detected. - // The error is likely path.ErrBadPattern but need not be. - if _, err := t.fsys.(fs.GlobFS).Glob(glob + "nonexist/[]"); err == nil { - t.errorf("%s: Glob(%#q): bad pattern not detected", dir, glob+"nonexist/[]") - } - - // Try to find a letter that appears in only some of the final names. - c := rune('a') - for ; c <= 'z'; c++ { - have, haveNot := false, false - for _, d := range list { - if strings.ContainsRune(d.Name(), c) { - have = true - } else { - haveNot = true - } - } - if have && haveNot { - break - } - } - if c > 'z' { - c = 'a' - } - glob += "*" + string(c) + "*" - - var want []string - for _, d := range list { - if strings.ContainsRune(d.Name(), c) { - want = append(want, path.Join(dir, d.Name())) - } - } - - names, err := t.fsys.(fs.GlobFS).Glob(glob) - if err != nil { - t.errorf("%s: Glob(%#q): %w", dir, glob, err) - return - } - if slices.Equal(want, names) { - return - } - - if !slices.IsSorted(names) { - t.errorf("%s: Glob(%#q): unsorted output:\n%s", dir, glob, strings.Join(names, "\n")) - slices.Sort(names) - } - - var problems []string - for len(want) > 0 || len(names) > 0 { - switch { - case len(want) > 0 && len(names) > 0 && want[0] == names[0]: - want, names = want[1:], names[1:] - case len(want) > 0 && (len(names) == 0 || want[0] < names[0]): - problems = append(problems, "missing: "+want[0]) - want = want[1:] - default: - problems = append(problems, "extra: "+names[0]) - names = names[1:] - } - } - t.errorf("%s: Glob(%#q): wrong output:\n%s", dir, glob, strings.Join(problems, "\n")) -} - -// checkStat checks that a direct stat of path matches entry, -// which was found in the parent's directory listing. -func (t *fsTester) checkStat(path string, entry fs.DirEntry) { - file, err := t.fsys.Open(path) - if err != nil { - t.errorf("%s: Open: %w", path, err) - return - } - info, err := file.Stat() - file.Close() - if err != nil { - t.errorf("%s: Stat: %w", path, err) - return - } - fentry := formatEntry(entry) - fientry := formatInfoEntry(info) - // Note: mismatch here is OK for symlink, because Open dereferences symlink. - if fentry != fientry && entry.Type()&fs.ModeSymlink == 0 { - t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, fientry) - } - - einfo, err := entry.Info() - if err != nil { - t.errorf("%s: entry.Info: %w", path, err) - return - } - finfo := formatInfo(info) - if entry.Type()&fs.ModeSymlink != 0 { - // For symlink, just check that entry.Info matches entry on common fields. - // Open deferences symlink, so info itself may differ. - feentry := formatInfoEntry(einfo) - if fentry != feentry { - t.errorf("%s: mismatch\n\tentry = %s\n\tentry.Info() = %s\n", path, fentry, feentry) - } - } else { - feinfo := formatInfo(einfo) - if feinfo != finfo { - t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfile.Stat() = %s\n", path, feinfo, finfo) - } - } - - // Stat should be the same as Open+Stat, even for symlinks. - info2, err := fs.Stat(t.fsys, path) - if err != nil { - t.errorf("%s: fs.Stat: %w", path, err) - return - } - finfo2 := formatInfo(info2) - if finfo2 != finfo { - t.errorf("%s: fs.Stat(...) = %s\n\twant %s", path, finfo2, finfo) - } - - if fsys, ok := t.fsys.(fs.StatFS); ok { - info2, err := fsys.Stat(path) - if err != nil { - t.errorf("%s: fsys.Stat: %w", path, err) - return - } - finfo2 := formatInfo(info2) - if finfo2 != finfo { - t.errorf("%s: fsys.Stat(...) = %s\n\twant %s", path, finfo2, finfo) - } - } - - t.checkReadLinkFS(path, einfo, fentry) -} - -// checkDirList checks that two directory lists contain the same files and file info. -// The order of the lists need not match. -func (t *fsTester) checkDirList(dir, desc string, list1, list2 []fs.DirEntry) { - old := make(map[string]fs.DirEntry) - checkMode := func(entry fs.DirEntry) { - if entry.IsDir() != (entry.Type()&fs.ModeDir != 0) { - if entry.IsDir() { - t.errorf("%s: ReadDir returned %s with IsDir() = true, Type() & ModeDir = 0", dir, entry.Name()) - } else { - t.errorf("%s: ReadDir returned %s with IsDir() = false, Type() & ModeDir = ModeDir", dir, entry.Name()) - } - } - } - - for _, entry1 := range list1 { - old[entry1.Name()] = entry1 - checkMode(entry1) - } - - var diffs []string - for _, entry2 := range list2 { - entry1 := old[entry2.Name()] - if entry1 == nil { - checkMode(entry2) - diffs = append(diffs, "+ "+formatEntry(entry2)) - continue - } - if formatEntry(entry1) != formatEntry(entry2) { - diffs = append(diffs, "- "+formatEntry(entry1), "+ "+formatEntry(entry2)) - } - delete(old, entry2.Name()) - } - for _, entry1 := range old { - diffs = append(diffs, "- "+formatEntry(entry1)) - } - - if len(diffs) == 0 { - return - } - - slices.SortFunc(diffs, func(a, b string) int { - fa := strings.Fields(a) - fb := strings.Fields(b) - // sort by name (i < j) and then +/- (j < i, because + < -) - return strings.Compare(fa[1]+" "+fb[0], fb[1]+" "+fa[0]) - }) - - t.errorf("%s: diff %s:\n\t%s", dir, desc, strings.Join(diffs, "\n\t")) -} - -// checkFile checks that basic file reading works correctly. -func (t *fsTester) checkFile(file string) { - t.files = append(t.files, file) - - // Read entire file. - f, err := t.fsys.Open(file) - if err != nil { - t.errorf("%s: Open: %w", file, err) - return - } - - data, err := io.ReadAll(f) - if err != nil { - f.Close() - t.errorf("%s: Open+ReadAll: %w", file, err) - return - } - - if err := f.Close(); err != nil { - t.errorf("%s: Close: %w", file, err) - } - - // Check that closing twice doesn't crash. - // The return value doesn't matter. - f.Close() - - // Check that ReadFile works if present. - if fsys, ok := t.fsys.(fs.ReadFileFS); ok { - data2, err := fsys.ReadFile(file) - if err != nil { - t.errorf("%s: fsys.ReadFile: %w", file, err) - return - } - t.checkFileRead(file, "ReadAll vs fsys.ReadFile", data, data2) - - // Modify the data and check it again. Modifying the - // returned byte slice should not affect the next call. - for i := range data2 { - data2[i]++ - } - data2, err = fsys.ReadFile(file) - if err != nil { - t.errorf("%s: second call to fsys.ReadFile: %w", file, err) - return - } - t.checkFileRead(file, "Readall vs second fsys.ReadFile", data, data2) - - t.checkBadPath(file, "ReadFile", - func(name string) error { _, err := fsys.ReadFile(name); return err }) - } - - // Check that fs.ReadFile works with t.fsys. - data2, err := fs.ReadFile(t.fsys, file) - if err != nil { - t.errorf("%s: fs.ReadFile: %w", file, err) - return - } - t.checkFileRead(file, "ReadAll vs fs.ReadFile", data, data2) - - // Use iotest.TestReader to check small reads, Seek, ReadAt. - f, err = t.fsys.Open(file) - if err != nil { - t.errorf("%s: second Open: %w", file, err) - return - } - defer f.Close() - if err := iotest.TestReader(f, data); err != nil { - t.errorf("%s: failed TestReader:\n\t%s", file, strings.ReplaceAll(err.Error(), "\n", "\n\t")) - } -} - -func (t *fsTester) checkFileRead(file, desc string, data1, data2 []byte) { - if string(data1) != string(data2) { - t.errorf("%s: %s: different data returned\n\t%q\n\t%q", file, desc, data1, data2) - return - } -} - -// checkOpen validates file opening behavior by attempting to open and then close the given file path. -func (t *fsTester) checkOpen(file string) { - t.checkBadPath(file, "Open", func(file string) error { - f, err := t.fsys.Open(file) - if err == nil { - f.Close() - } - return err - }) -} - -// checkBadPath checks that various invalid forms of file's name cannot be opened using open. -func (t *fsTester) checkBadPath(file string, desc string, open func(string) error) { - bad := []string{ - "/" + file, - file + "/.", - } - if file == "." { - bad = append(bad, "/") - } - if i := strings.Index(file, "/"); i >= 0 { - bad = append(bad, - file[:i]+"//"+file[i+1:], - file[:i]+"/./"+file[i+1:], - file[:i]+`\`+file[i+1:], - file[:i]+"/../"+file, - ) - } - if i := strings.LastIndex(file, "/"); i >= 0 { - bad = append(bad, - file[:i]+"//"+file[i+1:], - file[:i]+"/./"+file[i+1:], - file[:i]+`\`+file[i+1:], - file+"/../"+file[i+1:], - ) - } - - for _, b := range bad { - if err := open(b); err == nil { - t.errorf("%s: %s(%s) succeeded, want error", file, desc, b) - } - } -} diff --git a/testing/testing/fstest/testfs_readlinkfs.go b/testing/testing/fstest/testfs_readlinkfs.go deleted file mode 100644 index 8e33845e..00000000 --- a/testing/testing/fstest/testfs_readlinkfs.go +++ /dev/null @@ -1,25 +0,0 @@ -//go:build go1.25 -// +build go1.25 - -package fstest - -import "io/fs" - -func (t *fsTester) checkReadLinkFS(path string, einfo fs.FileInfo, fentry string) { - if fsys, ok := t.fsys.(fs.ReadLinkFS); ok { - info2, err := fsys.Lstat(path) - if err != nil { - t.errorf("%s: fsys.Lstat: %v", path, err) - return - } - fientry2 := formatInfoEntry(info2) - if fentry != fientry2 { - t.errorf("%s: mismatch:\n\tentry = %s\n\tfsys.Lstat(...) = %s", path, fentry, fientry2) - } - feinfo := formatInfo(einfo) - finfo2 := formatInfo(info2) - if feinfo != finfo2 { - t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfsys.Lstat(...) = %s\n", path, feinfo, finfo2) - } - } -} diff --git a/testing/testing/fstest/testfs_readlinkfs_compat.go b/testing/testing/fstest/testfs_readlinkfs_compat.go deleted file mode 100644 index e35d9e5d..00000000 --- a/testing/testing/fstest/testfs_readlinkfs_compat.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build !go1.25 -// +build !go1.25 - -package fstest - -import "io/fs" - -// No-op on Go versions before 1.25 since fs.ReadLinkFS doesn't exist. -func (t *fsTester) checkReadLinkFS(path string, einfo fs.FileInfo, fentry string) {} diff --git a/testing/testing/fstest/testfs_test.go b/testing/testing/fstest/testfs_test.go deleted file mode 100644 index 8bcf5cea..00000000 --- a/testing/testing/fstest/testfs_test.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2021 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 fstest - -import ( - "errors" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "io/fs" - "os" - "path/filepath" - "slices" - "strings" - "testing" -) - -func TestSymlink(t *testing.T) { - testenv.MustHaveSymlink(t) - - tmp := t.TempDir() - tmpfs := os.DirFS(tmp) - - if err := os.WriteFile(filepath.Join(tmp, "hello"), []byte("hello, world\n"), 0644); err != nil { - t.Fatal(err) - } - - if err := os.Symlink(filepath.Join(tmp, "hello"), filepath.Join(tmp, "hello.link")); err != nil { - t.Fatal(err) - } - if err := os.Symlink("hello", filepath.Join(tmp, "hello_rel.link")); err != nil { - t.Fatal(err) - } - - if err := TestFS(tmpfs, "hello", "hello.link"); err != nil { - t.Fatal(err) - } -} - -func TestDash(t *testing.T) { - m := MapFS{ - "a-b/a": {Data: []byte("a-b/a")}, - } - if err := TestFS(m, "a-b/a"); err != nil { - t.Error(err) - } -} - -type shuffledFS MapFS - -func (fsys shuffledFS) Open(name string) (fs.File, error) { - f, err := MapFS(fsys).Open(name) - if err != nil { - return nil, err - } - return &shuffledFile{File: f}, nil -} - -type shuffledFile struct{ fs.File } - -func (f *shuffledFile) ReadDir(n int) ([]fs.DirEntry, error) { - dirents, err := f.File.(fs.ReadDirFile).ReadDir(n) - // Shuffle in a deterministic way, all we care about is making sure that the - // list of directory entries is not is the lexicographic order. - // - // We do this to make sure that the TestFS test suite is not affected by the - // order of directory entries. - slices.SortFunc(dirents, func(a, b fs.DirEntry) int { - return strings.Compare(b.Name(), a.Name()) - }) - return dirents, err -} - -func TestShuffledFS(t *testing.T) { - fsys := shuffledFS{ - "tmp/one": {Data: []byte("1")}, - "tmp/two": {Data: []byte("2")}, - "tmp/three": {Data: []byte("3")}, - } - if err := TestFS(fsys, "tmp/one", "tmp/two", "tmp/three"); err != nil { - t.Error(err) - } -} - -// failPermFS is a filesystem that always fails with fs.ErrPermission. -type failPermFS struct{} - -func (f failPermFS) Open(name string) (fs.File, error) { - if !fs.ValidPath(name) { - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrInvalid} - } - return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrPermission} -} - -func TestTestFSWrappedErrors(t *testing.T) { - err := TestFS(failPermFS{}) - if err == nil { - t.Fatal("error expected") - } - t.Logf("Error (expecting wrapped fs.ErrPermission):\n%v", err) - - if !errors.Is(err, fs.ErrPermission) { - t.Errorf("error should be a wrapped ErrPermission: %#v", err) - } - - // TestFS is expected to return a list of errors. - // Enforce that the list can be extracted for browsing. - var errs interface{ Unwrap() []error } - if !errors.As(err, &errs) { - t.Errorf("caller should be able to extract the errors as a list: %#v", err) - } else { - for _, err := range errs.Unwrap() { - // ErrPermission is expected - // but any other error must be reported. - if !errors.Is(err, fs.ErrPermission) { - t.Errorf("unexpected error: %v", err) - } - } - } -} diff --git a/testing/testing/fuzz.go b/testing/testing/fuzz.go deleted file mode 100644 index c07d6a06..00000000 --- a/testing/testing/fuzz.go +++ /dev/null @@ -1,745 +0,0 @@ -// 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 testing - -import ( - "context" - "errors" - "flag" - "fmt" - "io" - "os" - "path/filepath" - "reflect" - "runtime" - "strings" - "time" -) - -func initFuzzFlags() { - matchFuzz = flag.String("test.fuzz", "", "run the fuzz test matching `regexp`") - flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely") - flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a failing input") - - fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored (for use only by cmd/go)") - isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values (for use only by cmd/go)") -} - -var ( - matchFuzz *string - fuzzDuration durationOrCountFlag - minimizeDuration = durationOrCountFlag{d: 60 * time.Second, allowZero: true} - fuzzCacheDir *string - isFuzzWorker *bool - - // corpusDir is the parent directory of the fuzz test's seed corpus within - // the package. - corpusDir = "testdata/fuzz" -) - -// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an -// internal error. This distinguishes internal errors from uncontrolled panics -// and other failures. Keep in sync with internal/fuzz.workerExitCode. -const fuzzWorkerExitCode = 70 - -// InternalFuzzTarget is an internal type but exported because it is -// cross-package; it is part of the implementation of the "go test" command. -type InternalFuzzTarget struct { - Name string - Fn func(f *F) -} - -// F is a type passed to fuzz tests. -// -// Fuzz tests run generated inputs against a provided fuzz target, which can -// find and report potential bugs in the code being tested. -// -// A fuzz test runs the seed corpus by default, which includes entries provided -// by [F.Add] and entries in the testdata/fuzz/ directory. After -// any necessary setup and calls to [F.Add], the fuzz test must then call -// [F.Fuzz] to provide the fuzz target. See the testing package documentation -// for an example, and see the [F.Fuzz] and [F.Add] method documentation for -// details. -// -// *F methods can only be called before [F.Fuzz]. Once the test is -// executing the fuzz target, only [*T] methods can be used. The only *F methods -// that are allowed in the [F.Fuzz] function are [F.Failed] and [F.Name]. -type F struct { - common - fstate *fuzzState - tstate *testState - - // inFuzzFn is true when the fuzz function is running. Most F methods cannot - // be called when inFuzzFn is true. - inFuzzFn bool - - // corpus is a set of seed corpus entries, added with F.Add and loaded - // from testdata. - corpus []corpusEntry - - result fuzzResult - fuzzCalled bool -} - -var _ TB = (*F)(nil) - -// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry. -// We use a type alias because we don't want to export this type, and we can't -// import internal/fuzz from testing. -type corpusEntry = struct { - Parent string - Path string - Data []byte - Values []any - Generation int - IsSeed bool -} - -// Helper marks the calling function as a test helper function. -// When printing file and line information, that function will be skipped. -// Helper may be called simultaneously from multiple goroutines. -func (f *F) Helper() { - if f.inFuzzFn { - panic("testing: f.Helper was called inside the fuzz target, use t.Helper instead") - } - - // common.Helper is inlined here. - // If we called it, it would mark F.Helper as the helper - // instead of the caller. - f.mu.Lock() - defer f.mu.Unlock() - if f.helperPCs == nil { - f.helperPCs = make(map[uintptr]struct{}) - } - // repeating code from callerName here to save walking a stack frame - var pc [1]uintptr - n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper - if n == 0 { - panic("testing: zero callers found") - } - if _, found := f.helperPCs[pc[0]]; !found { - f.helperPCs[pc[0]] = struct{}{} - f.helperNames = nil // map will be recreated next time it is needed - } -} - -// Fail marks the function as having failed but continues execution. -func (f *F) Fail() { - // (*F).Fail may be called by (*T).Fail, which we should allow. However, we - // shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function. - if f.inFuzzFn { - panic("testing: f.Fail was called inside the fuzz target, use t.Fail instead") - } - f.common.Helper() - f.common.Fail() -} - -// Skipped reports whether the test was skipped. -func (f *F) Skipped() bool { - // (*F).Skipped may be called by tRunner, which we should allow. However, we - // shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function. - if f.inFuzzFn { - panic("testing: f.Skipped was called inside the fuzz target, use t.Skipped instead") - } - f.common.Helper() - return f.common.Skipped() -} - -// Add will add the arguments to the seed corpus for the fuzz test. This will be -// a no-op if called after or within the fuzz target, and args must match the -// arguments for the fuzz target. -func (f *F) Add(args ...any) { - var values []any - for i := range args { - if t := reflect.TypeOf(args[i]); !supportedTypes[t] { - panic(fmt.Sprintf("testing: unsupported type to Add %v", t)) - } - values = append(values, args[i]) - } - f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))}) -} - -// supportedTypes represents all of the supported types which can be fuzzed. -var supportedTypes = map[reflect.Type]bool{ - reflect.TypeOf(([]byte)("")): true, - reflect.TypeOf((string)("")): true, - reflect.TypeOf((bool)(false)): true, - reflect.TypeOf((byte)(0)): true, - reflect.TypeOf((rune)(0)): true, - reflect.TypeOf((float32)(0)): true, - reflect.TypeOf((float64)(0)): true, - reflect.TypeOf((int)(0)): true, - reflect.TypeOf((int8)(0)): true, - reflect.TypeOf((int16)(0)): true, - reflect.TypeOf((int32)(0)): true, - reflect.TypeOf((int64)(0)): true, - reflect.TypeOf((uint)(0)): true, - reflect.TypeOf((uint8)(0)): true, - reflect.TypeOf((uint16)(0)): true, - reflect.TypeOf((uint32)(0)): true, - reflect.TypeOf((uint64)(0)): true, -} - -// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of -// arguments, those arguments will be added to the seed corpus. -// -// ff must be a function with no return value whose first argument is [*T] and -// whose remaining arguments are the types to be fuzzed. -// For example: -// -// f.Fuzz(func(t *testing.T, b []byte, i int) { ... }) -// -// The following types are allowed: []byte, string, bool, byte, rune, float32, -// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64. -// More types may be supported in the future. -// -// ff must not call any [*F] methods, e.g. [F.Log], [F.Error], [F.Skip]. Use -// the corresponding [*T] method instead. The only [*F] methods that are allowed in -// the F.Fuzz function are [F.Failed] and [F.Name]. -// -// This function should be fast and deterministic, and its behavior should not -// depend on shared state. No mutable input arguments, or pointers to them, -// should be retained between executions of the fuzz function, as the memory -// backing them may be mutated during a subsequent invocation. ff must not -// modify the underlying data of the arguments provided by the fuzzing engine. -// -// When fuzzing, F.Fuzz does not return until a problem is found, time runs out -// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz -// should be called exactly once, unless [F.Skip] or [F.Fail] is called beforehand. -func (f *F) Fuzz(ff any) { - if f.fuzzCalled { - panic("testing: F.Fuzz called more than once") - } - f.fuzzCalled = true - if f.failed { - return - } - f.Helper() - - // ff should be in the form func(*testing.T, ...interface{}) - fn := reflect.ValueOf(ff) - fnType := fn.Type() - if fnType.Kind() != reflect.Func { - panic("testing: F.Fuzz must receive a function") - } - if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) { - panic("testing: fuzz target must receive at least two arguments, where the first argument is a *T") - } - if fnType.NumOut() != 0 { - panic("testing: fuzz target must not return a value") - } - - // Save the types of the function to compare against the corpus. - var types []reflect.Type - for i := 1; i < fnType.NumIn(); i++ { - t := fnType.In(i) - if !supportedTypes[t] { - panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", t)) - } - types = append(types, t) - } - - // Load the testdata seed corpus. Check types of entries in the testdata - // corpus and entries declared with F.Add. - // - // Don't load the seed corpus if this is a worker process; we won't use it. - if f.fstate.mode != fuzzWorker { - for _, c := range f.corpus { - if err := f.fstate.deps.CheckCorpus(c.Values, types); err != nil { - // TODO(#48302): Report the source location of the F.Add call. - f.Fatal(err) - } - } - - // Load seed corpus - c, err := f.fstate.deps.ReadCorpus(filepath.Join(corpusDir, f.name), types) - if err != nil { - f.Fatal(err) - } - for i := range c { - c[i].IsSeed = true // these are all seed corpus values - if f.fstate.mode == fuzzCoordinator { - // If this is the coordinator process, zero the values, since we don't need - // to hold onto them. - c[i].Values = nil - } - } - - f.corpus = append(f.corpus, c...) - } - - // run calls fn on a given input, as a subtest with its own T. - // run is analogous to T.Run. The test filtering and cleanup works similarly. - // fn is called in its own goroutine. - run := func(captureOut io.Writer, e corpusEntry) (ok bool) { - if e.Values == nil { - // The corpusEntry must have non-nil Values in order to run the - // test. If Values is nil, it is a bug in our code. - panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path)) - } - if shouldFailFast() { - return true - } - testName := f.name - if e.Path != "" { - testName = fmt.Sprintf("%s/%s", testName, filepath.Base(e.Path)) - } - if f.tstate.isFuzzing { - // Don't preserve subtest names while fuzzing. If fn calls T.Run, - // there will be a very large number of subtests with duplicate names, - // which will use a large amount of memory. The subtest names aren't - // useful since there's no way to re-run them deterministically. - f.tstate.match.clearSubNames() - } - - ctx, cancelCtx := context.WithCancel(f.ctx) - - // Record the stack trace at the point of this call so that if the subtest - // function - which runs in a separate stack - is marked as a helper, we can - // continue walking the stack into the parent test. - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - t := &T{ - common: common{ - barrier: make(chan bool), - signal: make(chan bool), - name: testName, - parent: &f.common, - level: f.level + 1, - creator: pc[:n], - chatty: f.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: f.tstate, - } - if captureOut != nil { - // t.parent aliases f.common. - t.parent.w = captureOut - } - t.w = indenter{&t.common} - t.setOutputWriter() - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) - } - f.common.inFuzzFn, f.inFuzzFn = true, true - go tRunner(t, func(t *T) { - args := []reflect.Value{reflect.ValueOf(t)} - for _, v := range e.Values { - args = append(args, reflect.ValueOf(v)) - } - // Before resetting the current coverage, defer the snapshot so that - // we make sure it is called right before the tRunner function - // exits, regardless of whether it was executed cleanly, panicked, - // or if the fuzzFn called t.Fatal. - if f.tstate.isFuzzing { - defer f.fstate.deps.SnapshotCoverage() - f.fstate.deps.ResetCoverage() - } - fn.Call(args) - }) - <-t.signal - if t.chatty != nil && t.chatty.json { - t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name) - } - f.common.inFuzzFn, f.inFuzzFn = false, false - return !t.Failed() - } - - switch f.fstate.mode { - case fuzzCoordinator: - // Fuzzing is enabled, and this is the test process started by 'go test'. - // Act as the coordinator process, and coordinate workers to perform the - // actual fuzzing. - corpusTargetDir := filepath.Join(corpusDir, f.name) - cacheTargetDir := filepath.Join(*fuzzCacheDir, f.name) - err := f.fstate.deps.CoordinateFuzzing( - fuzzDuration.d, - int64(fuzzDuration.n), - minimizeDuration.d, - int64(minimizeDuration.n), - *parallel, - f.corpus, - types, - corpusTargetDir, - cacheTargetDir) - if err != nil { - f.result = fuzzResult{Error: err} - f.Fail() - fmt.Fprintf(f.w, "%v\n", err) - if crashErr, ok := err.(fuzzCrashError); ok { - crashPath := crashErr.CrashPath() - fmt.Fprintf(f.w, "Failing input written to %s\n", crashPath) - testName := filepath.Base(crashPath) - fmt.Fprintf(f.w, "To re-run:\ngo test -run=%s/%s\n", f.name, testName) - } - } - // TODO(jayconrod,katiehockman): Aggregate statistics across workers - // and add to FuzzResult (ie. time taken, num iterations) - - case fuzzWorker: - // Fuzzing is enabled, and this is a worker process. Follow instructions - // from the coordinator. - if err := f.fstate.deps.RunFuzzWorker(func(e corpusEntry) error { - // Don't write to f.w (which points to Stdout) if running from a - // fuzz worker. This would become very verbose, particularly during - // minimization. Return the error instead, and let the caller deal - // with the output. - var buf strings.Builder - if ok := run(&buf, e); !ok { - return errors.New(buf.String()) - } - return nil - }); err != nil { - // Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz. - // The worker will exit with fuzzWorkerExitCode, indicating this is a failure - // (and 'go test' should exit non-zero) but a failing input should not be recorded. - f.Errorf("communicating with fuzzing coordinator: %v", err) - } - - default: - // Fuzzing is not enabled, or will be done later. Only run the seed - // corpus now. - for _, e := range f.corpus { - name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path)) - if _, ok, _ := f.tstate.match.fullName(nil, name); ok { - run(f.w, e) - } - } - } -} - -func (f *F) report() { - if *isFuzzWorker || f.parent == nil { - return - } - dstr := fmtDuration(f.duration) - format := "--- %s: %s (%s)\n" - if f.Failed() { - f.flushToParent(f.name, format, "FAIL", f.name, dstr) - } else if f.chatty != nil { - if f.Skipped() { - f.flushToParent(f.name, format, "SKIP", f.name, dstr) - } else { - f.flushToParent(f.name, format, "PASS", f.name, dstr) - } - } -} - -// fuzzResult contains the results of a fuzz run. -type fuzzResult struct { - N int // The number of iterations. - T time.Duration // The total time taken. - Error error // Error is the error from the failing input -} - -func (r fuzzResult) String() string { - if r.Error == nil { - return "" - } - return r.Error.Error() -} - -// fuzzCrashError is satisfied by a failing input detected while fuzzing. -// These errors are written to the seed corpus and can be re-run with 'go test'. -// Errors within the fuzzing framework (like I/O errors between coordinator -// and worker processes) don't satisfy this interface. -type fuzzCrashError interface { - error - Unwrap() error - - // CrashPath returns the path of the subtest that corresponds to the saved - // crash input file in the seed corpus. The test can be re-run with go test - // -run=$test/$name $test is the fuzz test name, and $name is the - // filepath.Base of the string returned here. - CrashPath() string -} - -// fuzzState holds fields common to all fuzz tests. -type fuzzState struct { - deps testDeps - mode fuzzMode -} - -type fuzzMode uint8 - -const ( - seedCorpusOnly fuzzMode = iota - fuzzCoordinator - fuzzWorker -) - -// runFuzzTests runs the fuzz tests matching the pattern for -run. This will -// only run the (*F).Fuzz function for each seed corpus without using the -// fuzzing engine to generate or mutate inputs. -func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.Time) (ran, ok bool) { - ok = true - if len(fuzzTests) == 0 || *isFuzzWorker { - return ran, ok - } - m := newMatcher(deps.MatchString, *match, "-test.run", *skip) - var mFuzz *matcher - if *matchFuzz != "" { - mFuzz = newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip) - } - - for _, procs := range cpuList { - runtime.GOMAXPROCS(procs) - for i := uint(0); i < *count; i++ { - if shouldFailFast() { - break - } - - tstate := newTestState(*parallel, m) - tstate.deadline = deadline - fstate := &fuzzState{deps: deps, mode: seedCorpusOnly} - root := common{w: os.Stdout} // gather output in one place - if Verbose() { - root.chatty = newChattyPrinter(root.w) - } - for _, ft := range fuzzTests { - if shouldFailFast() { - break - } - testName, matched, _ := tstate.match.fullName(nil, ft.Name) - if !matched { - continue - } - if mFuzz != nil { - if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched { - // If this will be fuzzed, then don't run the seed corpus - // right now. That will happen later. - continue - } - } - ctx, cancelCtx := context.WithCancel(context.Background()) - f := &F{ - common: common{ - signal: make(chan bool), - barrier: make(chan bool), - name: testName, - parent: &root, - level: root.level + 1, - chatty: root.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: tstate, - fstate: fstate, - } - f.w = indenter{&f.common} - f.setOutputWriter() - if f.chatty != nil { - f.chatty.Updatef(f.name, "=== RUN %s\n", f.name) - } - go fRunner(f, ft.Fn) - <-f.signal - if f.chatty != nil && f.chatty.json { - f.chatty.Updatef(f.parent.name, "=== NAME %s\n", f.parent.name) - } - ok = ok && !f.Failed() - ran = ran || f.ran - } - if !ran { - // There were no tests to run on this iteration. - // This won't change, so no reason to keep trying. - break - } - } - } - - return ran, ok -} - -// runFuzzing runs the fuzz test matching the pattern for -fuzz. Only one such -// fuzz test must match. This will run the fuzzing engine to generate and -// mutate new inputs against the fuzz target. -// -// If fuzzing is disabled (-test.fuzz is not set), runFuzzing -// returns immediately. -func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) { - if len(fuzzTests) == 0 || *matchFuzz == "" { - return true - } - m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz", *skip) - tstate := newTestState(1, m) - tstate.isFuzzing = true - fstate := &fuzzState{ - deps: deps, - } - root := common{w: os.Stdout} - if *isFuzzWorker { - root.w = io.Discard - fstate.mode = fuzzWorker - } else { - fstate.mode = fuzzCoordinator - } - if Verbose() && !*isFuzzWorker { - root.chatty = newChattyPrinter(root.w) - } - var fuzzTest *InternalFuzzTarget - var testName string - var matched []string - for i := range fuzzTests { - name, ok, _ := tstate.match.fullName(nil, fuzzTests[i].Name) - if !ok { - continue - } - matched = append(matched, name) - fuzzTest = &fuzzTests[i] - testName = name - } - if len(matched) == 0 { - fmt.Fprintln(os.Stderr, "testing: warning: no fuzz tests to fuzz") - return true - } - if len(matched) > 1 { - fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one fuzz test: %v\n", matched) - return false - } - - ctx, cancelCtx := context.WithCancel(context.Background()) - f := &F{ - common: common{ - signal: make(chan bool), - barrier: nil, // T.Parallel has no effect when fuzzing. - name: testName, - parent: &root, - level: root.level + 1, - chatty: root.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - }, - fstate: fstate, - tstate: tstate, - } - f.w = indenter{&f.common} - f.setOutputWriter() - if f.chatty != nil { - f.chatty.Updatef(f.name, "=== RUN %s\n", f.name) - } - go fRunner(f, fuzzTest.Fn) - <-f.signal - if f.chatty != nil { - f.chatty.Updatef(f.parent.name, "=== NAME %s\n", f.parent.name) - } - return !f.failed -} - -// fRunner wraps a call to a fuzz test and ensures that cleanup functions are -// called and status flags are set. fRunner should be called in its own -// goroutine. To wait for its completion, receive from f.signal. -// -// fRunner is analogous to tRunner, which wraps subtests started with T.Run. -// Unit tests and fuzz tests work a little differently, so for now, these -// functions aren't consolidated. In particular, because there are no F.Run and -// F.Parallel methods, i.e., no fuzz sub-tests or parallel fuzz tests, a few -// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is -// called. -func fRunner(f *F, fn func(*F)) { - // When this goroutine is done, either because runtime.Goexit was called, a - // panic started, or fn returned normally, record the duration and send - // t.signal, indicating the fuzz test is done. - defer func() { - // Detect whether the fuzz test panicked or called runtime.Goexit - // without calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly - // replacing a nil panic value). Nothing should recover after fRunner - // unwinds, so this should crash the process and print stack. - // Unfortunately, recovering here adds stack frames, but the location of - // the original panic should still be - // clear. - f.checkRaces() - if f.Failed() { - numFailed.Add(1) - } - err := recover() - if err == nil { - f.mu.RLock() - fuzzNotCalled := !f.fuzzCalled && !f.skipped && !f.failed - if !f.finished && !f.skipped && !f.failed { - err = errNilPanicOrGoexit - } - f.mu.RUnlock() - if fuzzNotCalled && err == nil { - f.Error("returned without calling F.Fuzz, F.Fail, or F.Skip") - } - } - - // Use a deferred call to ensure that we report that the test is - // complete even if a cleanup function calls F.FailNow. See issue 41355. - didPanic := false - defer func() { - if !didPanic { - // Only report that the test is complete if it doesn't panic, - // as otherwise the test binary can exit before the panic is - // reported to the user. See issue 41479. - f.signal <- true - } - }() - - // If we recovered a panic or inappropriate runtime.Goexit, fail the test, - // flush the output log up to the root, then panic. - doPanic := func(err any) { - f.Fail() - if r := f.runCleanup(recoverAndReturnPanic); r != nil { - f.Logf("cleanup panicked with %v", r) - } - for root := &f.common; root.parent != nil; root = root.parent { - root.mu.Lock() - root.duration += highPrecisionTimeSince(root.start) - d := root.duration - root.mu.Unlock() - root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) - } - didPanic = true - panic(err) - } - if err != nil { - doPanic(err) - } - - // No panic or inappropriate Goexit. - f.duration += highPrecisionTimeSince(f.start) - - if len(f.sub) > 0 { - // Unblock inputs that called T.Parallel while running the seed corpus. - // This only affects fuzz tests run as normal tests. - // While fuzzing, T.Parallel has no effect, so f.sub is empty, and this - // branch is not taken. f.barrier is nil in that case. - f.tstate.release() - close(f.barrier) - // Wait for the subtests to complete. - for _, sub := range f.sub { - <-sub.signal - } - cleanupStart := highPrecisionTimeNow() - err := f.runCleanup(recoverAndReturnPanic) - f.duration += highPrecisionTimeSince(cleanupStart) - if err != nil { - doPanic(err) - } - } - - // Report after all subtests have finished. - f.report() - f.done = true - f.setRan() - }() - defer func() { - if len(f.sub) == 0 { - f.runCleanup(normalPanic) - } - }() - - f.start = highPrecisionTimeNow() - f.resetRaces() - fn(f) - - // Code beyond this point will not be executed when FailNow or SkipNow - // is invoked. - f.mu.Lock() - f.finished = true - f.mu.Unlock() -} diff --git a/testing/testing/helper_test.go b/testing/testing/helper_test.go deleted file mode 100644 index 09a2bc79..00000000 --- a/testing/testing/helper_test.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2017 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 ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "regexp" - "strings" - "testing" -) - -func TestTBHelper(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - testTestHelper(t) - - // Check that calling Helper from inside a top-level test function - // has no effect. - t.Helper() - t.Error("8") - return - } - - t.Parallel() - - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestTBHelper$") - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") - out, _ := cmd.CombinedOutput() - - want := `--- FAIL: TestTBHelper \([^)]+\) - helperfuncs_test.go:15: 0 - helperfuncs_test.go:47: 1 - helperfuncs_test.go:24: 2 - helperfuncs_test.go:49: 3 - helperfuncs_test.go:56: 4 - --- FAIL: TestTBHelper/sub \([^)]+\) - helperfuncs_test.go:59: 5 - helperfuncs_test.go:24: 6 - helperfuncs_test.go:58: 7 - --- FAIL: TestTBHelper/sub2 \([^)]+\) - helperfuncs_test.go:80: 11 - helperfuncs_test.go:84: recover 12 - helperfuncs_test.go:86: GenericFloat64 - helperfuncs_test.go:87: GenericInt - helper_test.go:22: 8 - helperfuncs_test.go:73: 9 - helperfuncs_test.go:69: 10 -` - if !regexp.MustCompile(want).Match(out) { - t.Errorf("got output:\n\n%s\nwant matching:\n\n%s", out, want) - } -} - -func TestTBHelperParallel(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - parallelTestHelper(t) - return - } - - t.Parallel() - - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestTBHelperParallel$") - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") - out, _ := cmd.CombinedOutput() - - t.Logf("output:\n%s", out) - - lines := strings.Split(strings.TrimSpace(string(out)), "\n") - - // We expect to see one "--- FAIL" line at the start - // of the log, five lines of "parallel" logging, - // and a final "FAIL" line at the end of the test. - const wantLines = 7 - - if len(lines) != wantLines { - t.Fatalf("parallelTestHelper gave %d lines of output; want %d", len(lines), wantLines) - } - want := "helperfuncs_test.go:24: parallel" - if got := strings.TrimSpace(lines[1]); got != want { - t.Errorf("got second output line %q; want %q", got, want) - } -} - -func BenchmarkTBHelper(b *testing.B) { - f1 := func() { - b.Helper() - } - f2 := func() { - b.Helper() - } - b.ResetTimer() - b.ReportAllocs() - for i := 0; i < b.N; i++ { - if i&1 == 0 { - f1() - } else { - f2() - } - } -} diff --git a/testing/testing/helperfuncs_test.go b/testing/testing/helperfuncs_test.go deleted file mode 100644 index f0295f35..00000000 --- a/testing/testing/helperfuncs_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2017 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 ( - "sync" - "testing" -) - -// The line numbering of this file is important for TestTBHelper. - -func notHelper(t *testing.T, msg string) { - t.Error(msg) -} - -func helper(t *testing.T, msg string) { - t.Helper() - t.Error(msg) -} - -func notHelperCallingHelper(t *testing.T, msg string) { - helper(t, msg) -} - -func helperCallingHelper(t *testing.T, msg string) { - t.Helper() - helper(t, msg) -} - -func genericHelper[G any](t *testing.T, msg string) { - t.Helper() - t.Error(msg) -} - -var genericIntHelper = genericHelper[int] - -func testTestHelper(t *testing.T) { - testHelper(t) -} - -func testHelper(t *testing.T) { - // Check combinations of directly and indirectly - // calling helper functions. - notHelper(t, "0") - helper(t, "1") - notHelperCallingHelper(t, "2") - helperCallingHelper(t, "3") - - // Check a function literal closing over t that uses Helper. - fn := func(msg string) { - t.Helper() - t.Error(msg) - } - fn("4") - - t.Run("sub", func(t *testing.T) { - helper(t, "5") - notHelperCallingHelper(t, "6") - // Check that calling Helper from inside a subtest entry function - // works as if it were in an ordinary function call. - t.Helper() - t.Error("7") - }) - - // Check that right caller is reported for func passed to Cleanup when - // multiple cleanup functions have been registered. - t.Cleanup(func() { - t.Helper() - t.Error("10") - }) - t.Cleanup(func() { - t.Helper() - t.Error("9") - }) - - // Check that helper-ness propagates up through subtests - // to helpers above. See https://golang.org/issue/44887. - helperSubCallingHelper(t, "11") - - // Check that helper-ness propagates up through panic/recover. - // See https://golang.org/issue/31154. - recoverHelper(t, "12") - - genericHelper[float64](t, "GenericFloat64") - genericIntHelper(t, "GenericInt") -} - -func parallelTestHelper(t *testing.T) { - var wg sync.WaitGroup - for i := 0; i < 5; i++ { - wg.Add(1) - go func() { - notHelperCallingHelper(t, "parallel") - wg.Done() - }() - } - wg.Wait() -} - -func helperSubCallingHelper(t *testing.T, msg string) { - t.Helper() - t.Run("sub2", func(t *testing.T) { - t.Helper() - t.Fatal(msg) - }) -} - -func recoverHelper(t *testing.T, msg string) { - t.Helper() - defer func() { - t.Helper() - if err := recover(); err != nil { - t.Errorf("recover %s", err) - } - }() - doPanic(t, msg) -} - -func doPanic(t *testing.T, msg string) { - t.Helper() - panic(msg) -} diff --git a/testing/testing/internal/testdeps/deps.go b/testing/testing/internal/testdeps/deps.go deleted file mode 100644 index 890c971b..00000000 --- a/testing/testing/internal/testdeps/deps.go +++ /dev/null @@ -1,240 +0,0 @@ -// 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 testdeps provides access to dependencies needed by test execution. -// -// This package is imported by the generated main package, which passes -// TestDeps into testing.Main. This allows tests to use packages at run time -// without making those packages direct dependencies of package testing. -// Direct dependencies of package testing are harder to write tests for. -package testdeps - -import ( - "bufio" - "context" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/fuzz" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testlog" - "io" - "os" - "os/signal" - "reflect" - "regexp" - "runtime/pprof" - "strings" - "sync" - "time" -) - -// Cover indicates whether coverage is enabled. -var Cover bool - -// TestDeps is an implementation of the testing.testDeps interface, -// suitable for passing to [testing.MainStart]. -type TestDeps struct{} - -var matchPat string -var matchRe *regexp.Regexp - -func (TestDeps) MatchString(pat, str string) (result bool, err error) { - if matchRe == nil || matchPat != pat { - matchPat = pat - matchRe, err = regexp.Compile(matchPat) - if err != nil { - return - } - } - return matchRe.MatchString(str), nil -} - -func (TestDeps) StartCPUProfile(w io.Writer) error { - return pprof.StartCPUProfile(w) -} - -func (TestDeps) StopCPUProfile() { - pprof.StopCPUProfile() -} - -func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error { - return pprof.Lookup(name).WriteTo(w, debug) -} - -// ImportPath is the import path of the testing binary, set by the generated main function. -var ImportPath string - -func (TestDeps) ImportPath() string { - return ImportPath -} - -// testLog implements testlog.Interface, logging actions by package os. -type testLog struct { - mu sync.Mutex - w *bufio.Writer - set bool -} - -func (l *testLog) Getenv(key string) { - l.add("getenv", key) -} - -func (l *testLog) Open(name string) { - l.add("open", name) -} - -func (l *testLog) Stat(name string) { - l.add("stat", name) -} - -func (l *testLog) Chdir(name string) { - l.add("chdir", name) -} - -// add adds the (op, name) pair to the test log. -func (l *testLog) add(op, name string) { - if strings.Contains(name, "\n") || name == "" { - return - } - - l.mu.Lock() - defer l.mu.Unlock() - if l.w == nil { - return - } - l.w.WriteString(op) - l.w.WriteByte(' ') - l.w.WriteString(name) - l.w.WriteByte('\n') -} - -var log testLog - -func (TestDeps) StartTestLog(w io.Writer) { - log.mu.Lock() - log.w = bufio.NewWriter(w) - if !log.set { - // Tests that define TestMain and then run m.Run multiple times - // will call StartTestLog/StopTestLog multiple times. - // Checking log.set avoids calling testlog.SetLogger multiple times - // (which will panic) and also avoids writing the header multiple times. - log.set = true - testlog.SetLogger(&log) - log.w.WriteString("# test log\n") // known to cmd/go/internal/test/test.go - } - log.mu.Unlock() -} - -func (TestDeps) StopTestLog() error { - log.mu.Lock() - defer log.mu.Unlock() - err := log.w.Flush() - log.w = nil - return err -} - -// SetPanicOnExit0 tells the os package whether to panic on os.Exit(0). -func (TestDeps) SetPanicOnExit0(v bool) { - testlog.SetPanicOnExit0(v) -} - -func (TestDeps) CoordinateFuzzing( - timeout time.Duration, - limit int64, - minimizeTimeout time.Duration, - minimizeLimit int64, - parallel int, - seed []fuzz.CorpusEntry, - types []reflect.Type, - corpusDir, - cacheDir string) (err error) { - // Fuzzing may be interrupted with a timeout or if the user presses ^C. - // In either case, we'll stop worker processes gracefully and save - // crashers and interesting values. - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - defer cancel() - err = fuzz.CoordinateFuzzing(ctx, fuzz.CoordinateFuzzingOpts{ - Log: os.Stderr, - Timeout: timeout, - Limit: limit, - MinimizeTimeout: minimizeTimeout, - MinimizeLimit: minimizeLimit, - Parallel: parallel, - Seed: seed, - Types: types, - CorpusDir: corpusDir, - CacheDir: cacheDir, - }) - if err == ctx.Err() { - return nil - } - return err -} - -func (TestDeps) RunFuzzWorker(fn func(fuzz.CorpusEntry) error) error { - // Worker processes may or may not receive a signal when the user presses ^C - // On POSIX operating systems, a signal sent to a process group is delivered - // to all processes in that group. This is not the case on Windows. - // If the worker is interrupted, return quickly and without error. - // If only the coordinator process is interrupted, it tells each worker - // process to stop by closing its "fuzz_in" pipe. - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) - defer cancel() - err := fuzz.RunFuzzWorker(ctx, fn) - if err == ctx.Err() { - return nil - } - return err -} - -func (TestDeps) ReadCorpus(dir string, types []reflect.Type) ([]fuzz.CorpusEntry, error) { - return fuzz.ReadCorpus(dir, types) -} - -func (TestDeps) CheckCorpus(vals []any, types []reflect.Type) error { - return fuzz.CheckCorpus(vals, types) -} - -func (TestDeps) ResetCoverage() { - fuzz.ResetCoverage() -} - -func (TestDeps) SnapshotCoverage() { - fuzz.SnapshotCoverage() -} - -var CoverMode string -var Covered string -var CoverSelectedPackages []string - -// These variables below are set at runtime (via code in testmain) to point -// to the equivalent functions in package internal/coverage/cfile; doing -// things this way allows us to have tests import internal/coverage/cfile -// only when -cover is in effect (as opposed to importing for all tests). -var ( - CoverSnapshotFunc func() float64 - CoverProcessTestDirFunc func(dir string, cfile string, cm string, cpkg string, w io.Writer, selpkgs []string) error - CoverMarkProfileEmittedFunc func(val bool) -) - -func (TestDeps) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) { - if CoverMode == "" { - return - } - return CoverMode, coverTearDown, CoverSnapshotFunc -} - -func coverTearDown(coverprofile string, gocoverdir string) (string, error) { - var err error - if gocoverdir == "" { - gocoverdir, err = os.MkdirTemp("", "gocoverdir") - if err != nil { - return "error setting GOCOVERDIR: bad os.MkdirTemp return", err - } - defer os.RemoveAll(gocoverdir) - } - CoverMarkProfileEmittedFunc(true) - cmode := CoverMode - if err := CoverProcessTestDirFunc(gocoverdir, coverprofile, cmode, Covered, os.Stdout, CoverSelectedPackages); err != nil { - return "error generating coverage report", err - } - return "", nil -} diff --git a/testing/testing/iotest/example_test.go b/testing/testing/iotest/example_test.go deleted file mode 100644 index 10f6bd38..00000000 --- a/testing/testing/iotest/example_test.go +++ /dev/null @@ -1,22 +0,0 @@ -// 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 iotest_test - -import ( - "errors" - "fmt" - "testing/iotest" -) - -func ExampleErrReader() { - // A reader that always returns a custom error. - r := iotest.ErrReader(errors.New("custom error")) - n, err := r.Read(nil) - fmt.Printf("n: %d\nerr: %q\n", n, err) - - // Output: - // n: 0 - // err: "custom error" -} diff --git a/testing/testing/iotest/logger.go b/testing/testing/iotest/logger.go deleted file mode 100644 index 10d0cb5b..00000000 --- a/testing/testing/iotest/logger.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2009 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 iotest - -import ( - "io" - "log" -) - -type writeLogger struct { - prefix string - w io.Writer -} - -func (l *writeLogger) Write(p []byte) (n int, err error) { - n, err = l.w.Write(p) - if err != nil { - log.Printf("%s %x: %v", l.prefix, p[0:n], err) - } else { - log.Printf("%s %x", l.prefix, p[0:n]) - } - return -} - -// NewWriteLogger returns a writer that behaves like w except -// that it logs (using [log.Printf]) each write to standard error, -// printing the prefix and the hexadecimal data written. -func NewWriteLogger(prefix string, w io.Writer) io.Writer { - return &writeLogger{prefix, w} -} - -type readLogger struct { - prefix string - r io.Reader -} - -func (l *readLogger) Read(p []byte) (n int, err error) { - n, err = l.r.Read(p) - if err != nil { - log.Printf("%s %x: %v", l.prefix, p[0:n], err) - } else { - log.Printf("%s %x", l.prefix, p[0:n]) - } - return -} - -// NewReadLogger returns a reader that behaves like r except -// that it logs (using [log.Printf]) each read to standard error, -// printing the prefix and the hexadecimal data read. -func NewReadLogger(prefix string, r io.Reader) io.Reader { - return &readLogger{prefix, r} -} diff --git a/testing/testing/iotest/logger_test.go b/testing/testing/iotest/logger_test.go deleted file mode 100644 index 7a7d0aa9..00000000 --- a/testing/testing/iotest/logger_test.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2019 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 iotest - -import ( - "bytes" - "errors" - "fmt" - "log" - "strings" - "testing" -) - -type errWriter struct { - err error -} - -func (w errWriter) Write([]byte) (int, error) { - return 0, w.err -} - -func TestWriteLogger(t *testing.T) { - olw := log.Writer() - olf := log.Flags() - olp := log.Prefix() - - // Revert the original log settings before we exit. - defer func() { - log.SetFlags(olf) - log.SetPrefix(olp) - log.SetOutput(olw) - }() - - lOut := new(strings.Builder) - log.SetPrefix("lw: ") - log.SetOutput(lOut) - log.SetFlags(0) - - lw := new(strings.Builder) - wl := NewWriteLogger("write:", lw) - if _, err := wl.Write([]byte("Hello, World!")); err != nil { - t.Fatalf("Unexpectedly failed to write: %v", err) - } - - if g, w := lw.String(), "Hello, World!"; g != w { - t.Errorf("WriteLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } - wantLogWithHex := fmt.Sprintf("lw: write: %x\n", "Hello, World!") - if g, w := lOut.String(), wantLogWithHex; g != w { - t.Errorf("WriteLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } -} - -func TestWriteLogger_errorOnWrite(t *testing.T) { - olw := log.Writer() - olf := log.Flags() - olp := log.Prefix() - - // Revert the original log settings before we exit. - defer func() { - log.SetFlags(olf) - log.SetPrefix(olp) - log.SetOutput(olw) - }() - - lOut := new(strings.Builder) - log.SetPrefix("lw: ") - log.SetOutput(lOut) - log.SetFlags(0) - - lw := errWriter{err: errors.New("Write Error!")} - wl := NewWriteLogger("write:", lw) - if _, err := wl.Write([]byte("Hello, World!")); err == nil { - t.Fatalf("Unexpectedly succeeded to write: %v", err) - } - - wantLogWithHex := fmt.Sprintf("lw: write: %x: %v\n", "", "Write Error!") - if g, w := lOut.String(), wantLogWithHex; g != w { - t.Errorf("WriteLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } -} - -func TestReadLogger(t *testing.T) { - olw := log.Writer() - olf := log.Flags() - olp := log.Prefix() - - // Revert the original log settings before we exit. - defer func() { - log.SetFlags(olf) - log.SetPrefix(olp) - log.SetOutput(olw) - }() - - lOut := new(strings.Builder) - log.SetPrefix("lr: ") - log.SetOutput(lOut) - log.SetFlags(0) - - data := []byte("Hello, World!") - p := make([]byte, len(data)) - lr := bytes.NewReader(data) - rl := NewReadLogger("read:", lr) - - n, err := rl.Read(p) - if err != nil { - t.Fatalf("Unexpectedly failed to read: %v", err) - } - - if g, w := p[:n], data; !bytes.Equal(g, w) { - t.Errorf("ReadLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } - - wantLogWithHex := fmt.Sprintf("lr: read: %x\n", "Hello, World!") - if g, w := lOut.String(), wantLogWithHex; g != w { - t.Errorf("ReadLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } -} - -func TestReadLogger_errorOnRead(t *testing.T) { - olw := log.Writer() - olf := log.Flags() - olp := log.Prefix() - - // Revert the original log settings before we exit. - defer func() { - log.SetFlags(olf) - log.SetPrefix(olp) - log.SetOutput(olw) - }() - - lOut := new(strings.Builder) - log.SetPrefix("lr: ") - log.SetOutput(lOut) - log.SetFlags(0) - - data := []byte("Hello, World!") - p := make([]byte, len(data)) - - lr := ErrReader(errors.New("io failure")) - rl := NewReadLogger("read", lr) - n, err := rl.Read(p) - if err == nil { - t.Fatalf("Unexpectedly succeeded to read: %v", err) - } - - wantLogWithHex := fmt.Sprintf("lr: read %x: io failure\n", p[:n]) - if g, w := lOut.String(), wantLogWithHex; g != w { - t.Errorf("ReadLogger mismatch\n\tgot: %q\n\twant: %q", g, w) - } -} diff --git a/testing/testing/iotest/reader.go b/testing/testing/iotest/reader.go deleted file mode 100644 index 8529e1c6..00000000 --- a/testing/testing/iotest/reader.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2009 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 iotest implements Readers and Writers useful mainly for testing. -package iotest - -import ( - "bytes" - "errors" - "fmt" - "io" -) - -// OneByteReader returns a Reader that implements -// each non-empty Read by reading one byte from r. -func OneByteReader(r io.Reader) io.Reader { return &oneByteReader{r} } - -type oneByteReader struct { - r io.Reader -} - -func (r *oneByteReader) Read(p []byte) (int, error) { - if len(p) == 0 { - return 0, nil - } - return r.r.Read(p[0:1]) -} - -// HalfReader returns a Reader that implements Read -// by reading half as many requested bytes from r. -func HalfReader(r io.Reader) io.Reader { return &halfReader{r} } - -type halfReader struct { - r io.Reader -} - -func (r *halfReader) Read(p []byte) (int, error) { - return r.r.Read(p[0 : (len(p)+1)/2]) -} - -// DataErrReader changes the way errors are handled by a Reader. Normally, a -// Reader returns an error (typically EOF) from the first Read call after the -// last piece of data is read. DataErrReader wraps a Reader and changes its -// behavior so the final error is returned along with the final data, instead -// of in the first call after the final data. -func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} } - -type dataErrReader struct { - r io.Reader - unread []byte - data []byte -} - -func (r *dataErrReader) Read(p []byte) (n int, err error) { - // loop because first call needs two reads: - // one to get data and a second to look for an error. - for { - if len(r.unread) == 0 { - n1, err1 := r.r.Read(r.data) - r.unread = r.data[0:n1] - err = err1 - } - if n > 0 || err != nil { - break - } - n = copy(p, r.unread) - r.unread = r.unread[n:] - } - return -} - -// ErrTimeout is a fake timeout error. -var ErrTimeout = errors.New("timeout") - -// TimeoutReader returns [ErrTimeout] on the second read -// with no data. Subsequent calls to read succeed. -func TimeoutReader(r io.Reader) io.Reader { return &timeoutReader{r, 0} } - -type timeoutReader struct { - r io.Reader - count int -} - -func (r *timeoutReader) Read(p []byte) (int, error) { - r.count++ - if r.count == 2 { - return 0, ErrTimeout - } - return r.r.Read(p) -} - -// ErrReader returns an [io.Reader] that returns 0, err from all Read calls. -func ErrReader(err error) io.Reader { - return &errReader{err: err} -} - -type errReader struct { - err error -} - -func (r *errReader) Read(p []byte) (int, error) { - return 0, r.err -} - -type smallByteReader struct { - r io.Reader - off int - n int -} - -func (r *smallByteReader) Read(p []byte) (int, error) { - if len(p) == 0 { - return 0, nil - } - r.n = r.n%3 + 1 - n := r.n - if n > len(p) { - n = len(p) - } - n, err := r.r.Read(p[0:n]) - if err != nil && err != io.EOF { - err = fmt.Errorf("Read(%d bytes at offset %d): %v", n, r.off, err) - } - r.off += n - return n, err -} - -// TestReader tests that reading from r returns the expected file content. -// It does reads of different sizes, until EOF. -// If r implements [io.ReaderAt] or [io.Seeker], TestReader also checks -// that those operations behave as they should. -// -// If TestReader finds any misbehaviors, it returns an error reporting them. -// The error text may span multiple lines. -func TestReader(r io.Reader, content []byte) error { - if len(content) > 0 { - n, err := r.Read(nil) - if n != 0 || err != nil { - return fmt.Errorf("Read(0) = %d, %v, want 0, nil", n, err) - } - } - - data, err := io.ReadAll(&smallByteReader{r: r}) - if err != nil { - return err - } - if !bytes.Equal(data, content) { - return fmt.Errorf("ReadAll(small amounts) = %q\n\twant %q", data, content) - } - n, err := r.Read(make([]byte, 10)) - if n != 0 || err != io.EOF { - return fmt.Errorf("Read(10) at EOF = %v, %v, want 0, EOF", n, err) - } - - if r, ok := r.(io.ReadSeeker); ok { - // Seek(0, 1) should report the current file position (EOF). - if off, err := r.Seek(0, 1); off != int64(len(content)) || err != nil { - return fmt.Errorf("Seek(0, 1) from EOF = %d, %v, want %d, nil", off, err, len(content)) - } - - // Seek backward partway through file, in two steps. - // If middle == 0, len(content) == 0, can't use the -1 and +1 seeks. - middle := len(content) - len(content)/3 - if middle > 0 { - if off, err := r.Seek(-1, 1); off != int64(len(content)-1) || err != nil { - return fmt.Errorf("Seek(-1, 1) from EOF = %d, %v, want %d, nil", -off, err, len(content)-1) - } - if off, err := r.Seek(int64(-len(content)/3), 1); off != int64(middle-1) || err != nil { - return fmt.Errorf("Seek(%d, 1) from %d = %d, %v, want %d, nil", -len(content)/3, len(content)-1, off, err, middle-1) - } - if off, err := r.Seek(+1, 1); off != int64(middle) || err != nil { - return fmt.Errorf("Seek(+1, 1) from %d = %d, %v, want %d, nil", middle-1, off, err, middle) - } - } - - // Seek(0, 1) should report the current file position (middle). - if off, err := r.Seek(0, 1); off != int64(middle) || err != nil { - return fmt.Errorf("Seek(0, 1) from %d = %d, %v, want %d, nil", middle, off, err, middle) - } - - // Reading forward should return the last part of the file. - data, err := io.ReadAll(&smallByteReader{r: r}) - if err != nil { - return fmt.Errorf("ReadAll from offset %d: %v", middle, err) - } - if !bytes.Equal(data, content[middle:]) { - return fmt.Errorf("ReadAll from offset %d = %q\n\twant %q", middle, data, content[middle:]) - } - - // Seek relative to end of file, but start elsewhere. - if off, err := r.Seek(int64(middle/2), 0); off != int64(middle/2) || err != nil { - return fmt.Errorf("Seek(%d, 0) from EOF = %d, %v, want %d, nil", middle/2, off, err, middle/2) - } - if off, err := r.Seek(int64(-len(content)/3), 2); off != int64(middle) || err != nil { - return fmt.Errorf("Seek(%d, 2) from %d = %d, %v, want %d, nil", -len(content)/3, middle/2, off, err, middle) - } - - // Reading forward should return the last part of the file (again). - data, err = io.ReadAll(&smallByteReader{r: r}) - if err != nil { - return fmt.Errorf("ReadAll from offset %d: %v", middle, err) - } - if !bytes.Equal(data, content[middle:]) { - return fmt.Errorf("ReadAll from offset %d = %q\n\twant %q", middle, data, content[middle:]) - } - - // Absolute seek & read forward. - if off, err := r.Seek(int64(middle/2), 0); off != int64(middle/2) || err != nil { - return fmt.Errorf("Seek(%d, 0) from EOF = %d, %v, want %d, nil", middle/2, off, err, middle/2) - } - data, err = io.ReadAll(r) - if err != nil { - return fmt.Errorf("ReadAll from offset %d: %v", middle/2, err) - } - if !bytes.Equal(data, content[middle/2:]) { - return fmt.Errorf("ReadAll from offset %d = %q\n\twant %q", middle/2, data, content[middle/2:]) - } - } - - if r, ok := r.(io.ReaderAt); ok { - data := make([]byte, len(content), len(content)+1) - for i := range data { - data[i] = 0xfe - } - n, err := r.ReadAt(data, 0) - if n != len(data) || err != nil && err != io.EOF { - return fmt.Errorf("ReadAt(%d, 0) = %v, %v, want %d, nil or EOF", len(data), n, err, len(data)) - } - if !bytes.Equal(data, content) { - return fmt.Errorf("ReadAt(%d, 0) = %q\n\twant %q", len(data), data, content) - } - - n, err = r.ReadAt(data[:1], int64(len(data))) - if n != 0 || err != io.EOF { - return fmt.Errorf("ReadAt(1, %d) = %v, %v, want 0, EOF", len(data), n, err) - } - - for i := range data { - data[i] = 0xfe - } - n, err = r.ReadAt(data[:cap(data)], 0) - if n != len(data) || err != io.EOF { - return fmt.Errorf("ReadAt(%d, 0) = %v, %v, want %d, EOF", cap(data), n, err, len(data)) - } - if !bytes.Equal(data, content) { - return fmt.Errorf("ReadAt(%d, 0) = %q\n\twant %q", len(data), data, content) - } - - for i := range data { - data[i] = 0xfe - } - for i := range data { - n, err = r.ReadAt(data[i:i+1], int64(i)) - if n != 1 || err != nil && (i != len(data)-1 || err != io.EOF) { - want := "nil" - if i == len(data)-1 { - want = "nil or EOF" - } - return fmt.Errorf("ReadAt(1, %d) = %v, %v, want 1, %s", i, n, err, want) - } - if data[i] != content[i] { - return fmt.Errorf("ReadAt(1, %d) = %q want %q", i, data[i:i+1], content[i:i+1]) - } - } - } - return nil -} diff --git a/testing/testing/iotest/reader_test.go b/testing/testing/iotest/reader_test.go deleted file mode 100644 index 1d222372..00000000 --- a/testing/testing/iotest/reader_test.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2019 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 iotest - -import ( - "bytes" - "errors" - "io" - "strings" - "testing" -) - -func TestOneByteReader_nonEmptyReader(t *testing.T) { - msg := "Hello, World!" - buf := new(bytes.Buffer) - buf.WriteString(msg) - - obr := OneByteReader(buf) - var b []byte - n, err := obr.Read(b) - if err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - - b = make([]byte, 3) - // Read from obr until EOF. - got := new(strings.Builder) - for i := 0; ; i++ { - n, err = obr.Read(b) - if err != nil { - break - } - if g, w := n, 1; g != w { - t.Errorf("Iteration #%d read %d bytes, want %d", i, g, w) - } - got.Write(b[:n]) - } - if g, w := err, io.EOF; g != w { - t.Errorf("Unexpected error after reading all bytes\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := got.String(), "Hello, World!"; g != w { - t.Errorf("Read mismatch\n\tGot: %q\n\tWant: %q", g, w) - } -} - -func TestOneByteReader_emptyReader(t *testing.T) { - r := new(bytes.Buffer) - - obr := OneByteReader(r) - var b []byte - if n, err := obr.Read(b); err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - - b = make([]byte, 5) - n, err := obr.Read(b) - if g, w := err, io.EOF; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } -} - -func TestHalfReader_nonEmptyReader(t *testing.T) { - msg := "Hello, World!" - buf := new(bytes.Buffer) - buf.WriteString(msg) - // empty read buffer - hr := HalfReader(buf) - var b []byte - n, err := hr.Read(b) - if err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - // non empty read buffer - b = make([]byte, 2) - got := new(strings.Builder) - for i := 0; ; i++ { - n, err = hr.Read(b) - if err != nil { - break - } - if g, w := n, 1; g != w { - t.Errorf("Iteration #%d read %d bytes, want %d", i, g, w) - } - got.Write(b[:n]) - } - if g, w := err, io.EOF; g != w { - t.Errorf("Unexpected error after reading all bytes\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := got.String(), "Hello, World!"; g != w { - t.Errorf("Read mismatch\n\tGot: %q\n\tWant: %q", g, w) - } -} - -func TestHalfReader_emptyReader(t *testing.T) { - r := new(bytes.Buffer) - - hr := HalfReader(r) - var b []byte - if n, err := hr.Read(b); err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - - b = make([]byte, 5) - n, err := hr.Read(b) - if g, w := err, io.EOF; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } -} - -func TestTimeOutReader_nonEmptyReader(t *testing.T) { - msg := "Hello, World!" - buf := new(bytes.Buffer) - buf.WriteString(msg) - // empty read buffer - tor := TimeoutReader(buf) - var b []byte - n, err := tor.Read(b) - if err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - // Second call should timeout - n, err = tor.Read(b) - if g, w := err, ErrTimeout; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } - // non empty read buffer - tor2 := TimeoutReader(buf) - b = make([]byte, 3) - if n, err := tor2.Read(b); err != nil || n == 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - // Second call should timeout - n, err = tor2.Read(b) - if g, w := err, ErrTimeout; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } -} - -func TestTimeOutReader_emptyReader(t *testing.T) { - r := new(bytes.Buffer) - // empty read buffer - tor := TimeoutReader(r) - var b []byte - if n, err := tor.Read(b); err != nil || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - // Second call should timeout - n, err := tor.Read(b) - if g, w := err, ErrTimeout; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } - // non empty read buffer - tor2 := TimeoutReader(r) - b = make([]byte, 5) - if n, err := tor2.Read(b); err != io.EOF || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - // Second call should timeout - n, err = tor2.Read(b) - if g, w := err, ErrTimeout; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } -} - -func TestDataErrReader_nonEmptyReader(t *testing.T) { - msg := "Hello, World!" - buf := new(bytes.Buffer) - buf.WriteString(msg) - - der := DataErrReader(buf) - - b := make([]byte, 3) - got := new(strings.Builder) - var n int - var err error - for { - n, err = der.Read(b) - got.Write(b[:n]) - if err != nil { - break - } - } - if err != io.EOF || n == 0 { - t.Errorf("Last Read returned n=%d err=%v", n, err) - } - if g, w := got.String(), "Hello, World!"; g != w { - t.Errorf("Read mismatch\n\tGot: %q\n\tWant: %q", g, w) - } -} - -func TestDataErrReader_emptyReader(t *testing.T) { - r := new(bytes.Buffer) - - der := DataErrReader(r) - var b []byte - if n, err := der.Read(b); err != io.EOF || n != 0 { - t.Errorf("Empty buffer read returned n=%d err=%v", n, err) - } - - b = make([]byte, 5) - n, err := der.Read(b) - if g, w := err, io.EOF; g != w { - t.Errorf("Error mismatch\n\tGot: %v\n\tWant: %v", g, w) - } - if g, w := n, 0; g != w { - t.Errorf("Unexpectedly read %d bytes, wanted %d", g, w) - } -} - -func TestErrReader(t *testing.T) { - cases := []struct { - name string - err error - }{ - {"nil error", nil}, - {"non-nil error", errors.New("io failure")}, - {"io.EOF", io.EOF}, - } - - for _, tt := range cases { - tt := tt - t.Run(tt.name, func(t *testing.T) { - n, err := ErrReader(tt.err).Read(nil) - if err != tt.err { - t.Fatalf("Error mismatch\nGot: %v\nWant: %v", err, tt.err) - } - if n != 0 { - t.Fatalf("Byte count mismatch: got %d want 0", n) - } - }) - } -} - -func TestStringsReader(t *testing.T) { - const msg = "Now is the time for all good gophers." - - r := strings.NewReader(msg) - if err := TestReader(r, []byte(msg)); err != nil { - t.Fatal(err) - } -} diff --git a/testing/testing/iotest/writer.go b/testing/testing/iotest/writer.go deleted file mode 100644 index af61ab85..00000000 --- a/testing/testing/iotest/writer.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2009 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 iotest - -import "io" - -// TruncateWriter returns a Writer that writes to w -// but stops silently after n bytes. -func TruncateWriter(w io.Writer, n int64) io.Writer { - return &truncateWriter{w, n} -} - -type truncateWriter struct { - w io.Writer - n int64 -} - -func (t *truncateWriter) Write(p []byte) (n int, err error) { - if t.n <= 0 { - return len(p), nil - } - // real write - n = len(p) - if int64(n) > t.n { - n = int(t.n) - } - n, err = t.w.Write(p[0:n]) - t.n -= int64(n) - if err == nil { - n = len(p) - } - return -} diff --git a/testing/testing/iotest/writer_test.go b/testing/testing/iotest/writer_test.go deleted file mode 100644 index 27625133..00000000 --- a/testing/testing/iotest/writer_test.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 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 iotest - -import ( - "strings" - "testing" -) - -var truncateWriterTests = []struct { - in string - want string - trunc int64 - n int -}{ - {"hello", "", -1, 5}, - {"world", "", 0, 5}, - {"abcde", "abc", 3, 5}, - {"edcba", "edcba", 7, 5}, -} - -func TestTruncateWriter(t *testing.T) { - for _, tt := range truncateWriterTests { - buf := new(strings.Builder) - tw := TruncateWriter(buf, tt.trunc) - n, err := tw.Write([]byte(tt.in)) - if err != nil { - t.Errorf("Unexpected error %v for\n\t%+v", err, tt) - } - if g, w := buf.String(), tt.want; g != w { - t.Errorf("got %q, expected %q", g, w) - } - if g, w := n, tt.n; g != w { - t.Errorf("read %d bytes, but expected to have read %d bytes for\n\t%+v", g, w, tt) - } - } -} diff --git a/testing/testing/loop_test.go b/testing/testing/loop_test.go deleted file mode 100644 index 743cbe64..00000000 --- a/testing/testing/loop_test.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2024 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 - -import ( - "bytes" - "strings" -) - -// See also TestBenchmarkBLoop* in other files. - -func TestBenchmarkBLoop(t *T) { - var initialStart highPrecisionTime - var firstStart highPrecisionTime - var scaledStart highPrecisionTime - var runningEnd bool - runs := 0 - iters := 0 - firstBN := 0 - restBN := 0 - finalBN := 0 - bRet := Benchmark(func(b *B) { - initialStart = b.start - runs++ - for b.Loop() { - if iters == 0 { - firstStart = b.start - firstBN = b.N - } else { - restBN = max(restBN, b.N) - } - if iters == 1 { - scaledStart = b.start - } - iters++ - } - finalBN = b.N - runningEnd = b.timerOn - }) - // Verify that a b.Loop benchmark is invoked just once. - if runs != 1 { - t.Errorf("want runs == 1, got %d", runs) - } - // Verify that at least one iteration ran. - if iters == 0 { - t.Fatalf("no iterations ran") - } - // Verify that b.N, bRet.N, and the b.Loop() iteration count match. - if finalBN != iters || bRet.N != iters { - t.Errorf("benchmark iterations mismatch: %d loop iterations, final b.N=%d, bRet.N=%d", iters, finalBN, bRet.N) - } - // Verify that b.N was 0 inside the loop - if firstBN != 0 { - t.Errorf("want b.N == 0 on first iteration, got %d", firstBN) - } - if restBN != 0 { - t.Errorf("want b.N == 0 on subsequent iterations, got %d", restBN) - } - // Make sure the benchmark ran for an appropriate amount of time. - if bRet.T < benchTime.d { - t.Fatalf("benchmark ran for %s, want >= %s", bRet.T, benchTime.d) - } - // Verify that the timer is reset on the first loop, and then left alone. - if firstStart == initialStart { - t.Errorf("b.Loop did not reset the timer") - } - if scaledStart != firstStart { - t.Errorf("b.Loop stops and restarts the timer during iteration") - } - // Verify that it stopped the timer after the last loop. - if runningEnd { - t.Errorf("timer was still running after last iteration") - } -} - -func TestBenchmarkBLoopBreak(t *T) { - var bState *B - var bLog bytes.Buffer - bRet := Benchmark(func(b *B) { - // The Benchmark function provides no access to the failure state and - // discards the log, so capture the B and save its log. - bState = b - b.common.w = &bLog - - for i := 0; b.Loop(); i++ { - if i == 2 { - break - } - } - }) - if !bState.failed { - t.Errorf("benchmark should have failed") - } - const wantLog = "benchmark function returned without B.Loop" - if log := bLog.String(); !strings.Contains(log, wantLog) { - t.Errorf("missing error %q in output:\n%s", wantLog, log) - } - // A benchmark that exits early should not report its target iteration count - // because it's not meaningful. - if bRet.N != 0 { - t.Errorf("want N == 0, got %d", bRet.N) - } -} - -func TestBenchmarkBLoopError(t *T) { - // Test that a benchmark that exits early because of an error doesn't *also* - // complain that the benchmark exited early. - var bState *B - var bLog bytes.Buffer - bRet := Benchmark(func(b *B) { - bState = b - b.common.w = &bLog - - for i := 0; b.Loop(); i++ { - b.Error("error") - return - } - }) - if !bState.failed { - t.Errorf("benchmark should have failed") - } - const noWantLog = "benchmark function returned without B.Loop" - if log := bLog.String(); strings.Contains(log, noWantLog) { - t.Errorf("unexpected error %q in output:\n%s", noWantLog, log) - } - if bRet.N != 0 { - t.Errorf("want N == 0, got %d", bRet.N) - } -} - -func TestBenchmarkBLoopStop(t *T) { - var bState *B - var bLog bytes.Buffer - bRet := Benchmark(func(b *B) { - bState = b - b.common.w = &bLog - - for i := 0; b.Loop(); i++ { - b.StopTimer() - } - }) - if !bState.failed { - t.Errorf("benchmark should have failed") - } - const wantLog = "B.Loop called with timer stopped" - if log := bLog.String(); !strings.Contains(log, wantLog) { - t.Errorf("missing error %q in output:\n%s", wantLog, log) - } - if bRet.N != 0 { - t.Errorf("want N == 0, got %d", bRet.N) - } -} diff --git a/testing/testing/match.go b/testing/testing/match.go deleted file mode 100644 index 84804dc2..00000000 --- a/testing/testing/match.go +++ /dev/null @@ -1,317 +0,0 @@ -// 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 testing - -import ( - "fmt" - "os" - "strconv" - "strings" - "sync" -) - -// matcher sanitizes, uniques, and filters names of subtests and subbenchmarks. -type matcher struct { - filter filterMatch - skip filterMatch - matchFunc func(pat, str string) (bool, error) - - mu sync.Mutex - - // subNames is used to deduplicate subtest names. - // Each key is the subtest name joined to the deduplicated name of the parent test. - // Each value is the count of the number of occurrences of the given subtest name - // already seen. - subNames map[string]int32 -} - -type filterMatch interface { - // matches checks the name against the receiver's pattern strings using the - // given match function. - matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) - - // verify checks that the receiver's pattern strings are valid filters by - // calling the given match function. - verify(name string, matchString func(pat, str string) (bool, error)) error -} - -// simpleMatch matches a test name if all of the pattern strings match in -// sequence. -type simpleMatch []string - -// alternationMatch matches a test name if one of the alternations match. -type alternationMatch []filterMatch - -// TODO: fix test_main to avoid race and improve caching, also allowing to -// eliminate this Mutex. -var matchMutex sync.Mutex - -func allMatcher() *matcher { - return newMatcher(nil, "", "", "") -} - -func newMatcher(matchString func(pat, str string) (bool, error), patterns, name, skips string) *matcher { - var filter, skip filterMatch - if patterns == "" { - filter = simpleMatch{} // always partial true - } else { - filter = splitRegexp(patterns) - if err := filter.verify(name, matchString); err != nil { - fmt.Fprintf(os.Stderr, "testing: invalid regexp for %s\n", err) - os.Exit(1) - } - } - if skips == "" { - skip = alternationMatch{} // always false - } else { - skip = splitRegexp(skips) - if err := skip.verify("-test.skip", matchString); err != nil { - fmt.Fprintf(os.Stderr, "testing: invalid regexp for %v\n", err) - os.Exit(1) - } - } - return &matcher{ - filter: filter, - skip: skip, - matchFunc: matchString, - subNames: map[string]int32{}, - } -} - -func (m *matcher) fullName(c *common, subname string) (name string, ok, partial bool) { - name = subname - - m.mu.Lock() - defer m.mu.Unlock() - - if c != nil && c.level > 0 { - name = m.unique(c.name, rewrite(subname)) - } - - matchMutex.Lock() - defer matchMutex.Unlock() - - // We check the full array of paths each time to allow for the case that a pattern contains a '/'. - elem := strings.Split(name, "/") - - // filter must match. - // accept partial match that may produce full match later. - ok, partial = m.filter.matches(elem, m.matchFunc) - if !ok { - return name, false, false - } - - // skip must not match. - // ignore partial match so we can get to more precise match later. - skip, partialSkip := m.skip.matches(elem, m.matchFunc) - if skip && !partialSkip { - return name, false, false - } - - return name, ok, partial -} - -// clearSubNames clears the matcher's internal state, potentially freeing -// memory. After this is called, T.Name may return the same strings as it did -// for earlier subtests. -func (m *matcher) clearSubNames() { - m.mu.Lock() - defer m.mu.Unlock() - clear(m.subNames) -} - -func (m simpleMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { - for i, s := range name { - if i >= len(m) { - break - } - if ok, _ := matchString(m[i], s); !ok { - return false, false - } - } - return true, len(name) < len(m) -} - -func (m simpleMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { - for i, s := range m { - m[i] = rewrite(s) - } - // Verify filters before doing any processing. - for i, s := range m { - if _, err := matchString(s, "non-empty"); err != nil { - return fmt.Errorf("element %d of %s (%q): %s", i, name, s, err) - } - } - return nil -} - -func (m alternationMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { - for _, m := range m { - if ok, partial = m.matches(name, matchString); ok { - return ok, partial - } - } - return false, false -} - -func (m alternationMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { - for i, m := range m { - if err := m.verify(name, matchString); err != nil { - return fmt.Errorf("alternation %d of %s", i, err) - } - } - return nil -} - -func splitRegexp(s string) filterMatch { - a := make(simpleMatch, 0, strings.Count(s, "/")) - b := make(alternationMatch, 0, strings.Count(s, "|")) - cs := 0 - cp := 0 - for i := 0; i < len(s); { - switch s[i] { - case '[': - cs++ - case ']': - if cs--; cs < 0 { // An unmatched ']' is legal. - cs = 0 - } - case '(': - if cs == 0 { - cp++ - } - case ')': - if cs == 0 { - cp-- - } - case '\\': - i++ - case '/': - if cs == 0 && cp == 0 { - a = append(a, s[:i]) - s = s[i+1:] - i = 0 - continue - } - case '|': - if cs == 0 && cp == 0 { - a = append(a, s[:i]) - s = s[i+1:] - i = 0 - b = append(b, a) - a = make(simpleMatch, 0, len(a)) - continue - } - } - i++ - } - - a = append(a, s) - if len(b) == 0 { - return a - } - return append(b, a) -} - -// unique creates a unique name for the given parent and subname by affixing it -// with one or more counts, if necessary. -func (m *matcher) unique(parent, subname string) string { - base := parent + "/" + subname - - for { - n := m.subNames[base] - if n < 0 { - panic("subtest count overflow") - } - m.subNames[base] = n + 1 - - if n == 0 && subname != "" { - prefix, nn := parseSubtestNumber(base) - if len(prefix) < len(base) && nn < m.subNames[prefix] { - // This test is explicitly named like "parent/subname#NN", - // and #NN was already used for the NNth occurrence of "parent/subname". - // Loop to add a disambiguating suffix. - continue - } - return base - } - - name := fmt.Sprintf("%s#%02d", base, n) - if m.subNames[name] != 0 { - // This is the nth occurrence of base, but the name "parent/subname#NN" - // collides with the first occurrence of a subtest *explicitly* named - // "parent/subname#NN". Try the next number. - continue - } - - return name - } -} - -// parseSubtestNumber splits a subtest name into a "#%02d"-formatted int32 -// suffix (if present), and a prefix preceding that suffix (always). -func parseSubtestNumber(s string) (prefix string, nn int32) { - i := strings.LastIndex(s, "#") - if i < 0 { - return s, 0 - } - - prefix, suffix := s[:i], s[i+1:] - if len(suffix) < 2 || (len(suffix) > 2 && suffix[0] == '0') { - // Even if suffix is numeric, it is not a possible output of a "%02" format - // string: it has either too few digits or too many leading zeroes. - return s, 0 - } - if suffix == "00" { - if !strings.HasSuffix(prefix, "/") { - // We only use "#00" as a suffix for subtests named with the empty - // string — it isn't a valid suffix if the subtest name is non-empty. - return s, 0 - } - } - - n, err := strconv.ParseInt(suffix, 10, 32) - if err != nil || n < 0 { - return s, 0 - } - return prefix, int32(n) -} - -// rewrite rewrites a subname to having only printable characters and no white -// space. -func rewrite(s string) string { - b := []byte{} - for _, r := range s { - switch { - case isSpace(r): - b = append(b, '_') - case !strconv.IsPrint(r): - s := strconv.QuoteRune(r) - b = append(b, s[1:len(s)-1]...) - default: - b = append(b, string(r)...) - } - } - return string(b) -} - -func isSpace(r rune) bool { - if r < 0x2000 { - switch r { - // Note: not the same as Unicode Z class. - case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680: - return true - } - } else { - if r <= 0x200a { - return true - } - switch r { - case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000: - return true - } - } - return false -} diff --git a/testing/testing/match_test.go b/testing/testing/match_test.go deleted file mode 100644 index d31efbc9..00000000 --- a/testing/testing/match_test.go +++ /dev/null @@ -1,263 +0,0 @@ -// 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 testing - -import ( - "fmt" - "reflect" - "regexp" - "strings" - "unicode" -) - -func init() { - testingTesting = true -} - -// Verify that our IsSpace agrees with unicode.IsSpace. -func TestIsSpace(t *T) { - n := 0 - for r := rune(0); r <= unicode.MaxRune; r++ { - if isSpace(r) != unicode.IsSpace(r) { - t.Errorf("IsSpace(%U)=%t incorrect", r, isSpace(r)) - n++ - if n > 10 { - return - } - } - } -} - -func TestSplitRegexp(t *T) { - res := func(s ...string) filterMatch { return simpleMatch(s) } - alt := func(m ...filterMatch) filterMatch { return alternationMatch(m) } - testCases := []struct { - pattern string - result filterMatch - }{ - // Correct patterns - // If a regexp pattern is correct, all split regexps need to be correct - // as well. - {"", res("")}, - {"/", res("", "")}, - {"//", res("", "", "")}, - {"A", res("A")}, - {"A/B", res("A", "B")}, - {"A/B/", res("A", "B", "")}, - {"/A/B/", res("", "A", "B", "")}, - {"[A]/(B)", res("[A]", "(B)")}, - {"[/]/[/]", res("[/]", "[/]")}, - {"[/]/[:/]", res("[/]", "[:/]")}, - {"/]", res("", "]")}, - {"]/", res("]", "")}, - {"]/[/]", res("]", "[/]")}, - {`([)/][(])`, res(`([)/][(])`)}, - {"[(]/[)]", res("[(]", "[)]")}, - - {"A/B|C/D", alt(res("A", "B"), res("C", "D"))}, - - // Faulty patterns - // Errors in original should produce at least one faulty regexp in results. - {")/", res(")/")}, - {")/(/)", res(")/(", ")")}, - {"a[/)b", res("a[/)b")}, - {"(/]", res("(/]")}, - {"(/", res("(/")}, - {"[/]/[/", res("[/]", "[/")}, - {`\p{/}`, res(`\p{`, "}")}, - {`\p/`, res(`\p`, "")}, - {`[[:/:]]`, res(`[[:/:]]`)}, - } - for _, tc := range testCases { - a := splitRegexp(tc.pattern) - if !reflect.DeepEqual(a, tc.result) { - t.Errorf("splitRegexp(%q) = %#v; want %#v", tc.pattern, a, tc.result) - } - - // If there is any error in the pattern, one of the returned subpatterns - // needs to have an error as well. - if _, err := regexp.Compile(tc.pattern); err != nil { - ok := true - if err := a.verify("", regexp.MatchString); err != nil { - ok = false - } - if ok { - t.Errorf("%s: expected error in any of %q", tc.pattern, a) - } - } - } -} - -func TestMatcher(t *T) { - testCases := []struct { - pattern string - skip string - parent, sub string - ok bool - partial bool - }{ - // Behavior without subtests. - {"", "", "", "TestFoo", true, false}, - {"TestFoo", "", "", "TestFoo", true, false}, - {"TestFoo/", "", "", "TestFoo", true, true}, - {"TestFoo/bar/baz", "", "", "TestFoo", true, true}, - {"TestFoo", "", "", "TestBar", false, false}, - {"TestFoo/", "", "", "TestBar", false, false}, - {"TestFoo/bar/baz", "", "", "TestBar/bar/baz", false, false}, - {"", "TestBar", "", "TestFoo", true, false}, - {"", "TestBar", "", "TestBar", false, false}, - - // Skipping a non-existent test doesn't change anything. - {"", "TestFoo/skipped", "", "TestFoo", true, false}, - {"TestFoo", "TestFoo/skipped", "", "TestFoo", true, false}, - {"TestFoo/", "TestFoo/skipped", "", "TestFoo", true, true}, - {"TestFoo/bar/baz", "TestFoo/skipped", "", "TestFoo", true, true}, - {"TestFoo", "TestFoo/skipped", "", "TestBar", false, false}, - {"TestFoo/", "TestFoo/skipped", "", "TestBar", false, false}, - {"TestFoo/bar/baz", "TestFoo/skipped", "", "TestBar/bar/baz", false, false}, - - // with subtests - {"", "", "TestFoo", "x", true, false}, - {"TestFoo", "", "TestFoo", "x", true, false}, - {"TestFoo/", "", "TestFoo", "x", true, false}, - {"TestFoo/bar/baz", "", "TestFoo", "bar", true, true}, - - {"", "TestFoo/skipped", "TestFoo", "x", true, false}, - {"TestFoo", "TestFoo/skipped", "TestFoo", "x", true, false}, - {"TestFoo", "TestFoo/skipped", "TestFoo", "skipped", false, false}, - {"TestFoo/", "TestFoo/skipped", "TestFoo", "x", true, false}, - {"TestFoo/bar/baz", "TestFoo/skipped", "TestFoo", "bar", true, true}, - - // Subtest with a '/' in its name still allows for copy and pasted names - // to match. - {"TestFoo/bar/baz", "", "TestFoo", "bar/baz", true, false}, - {"TestFoo/bar/baz", "TestFoo/bar/baz", "TestFoo", "bar/baz", false, false}, - {"TestFoo/bar/baz", "TestFoo/bar/baz/skip", "TestFoo", "bar/baz", true, false}, - {"TestFoo/bar/baz", "", "TestFoo/bar", "baz", true, false}, - {"TestFoo/bar/baz", "", "TestFoo", "x", false, false}, - {"TestFoo", "", "TestBar", "x", false, false}, - {"TestFoo/", "", "TestBar", "x", false, false}, - {"TestFoo/bar/baz", "", "TestBar", "x/bar/baz", false, false}, - - {"A/B|C/D", "", "TestA", "B", true, false}, - {"A/B|C/D", "", "TestC", "D", true, false}, - {"A/B|C/D", "", "TestA", "C", false, false}, - - // subtests only - {"", "", "TestFoo", "x", true, false}, - {"/", "", "TestFoo", "x", true, false}, - {"./", "", "TestFoo", "x", true, false}, - {"./.", "", "TestFoo", "x", true, false}, - {"/bar/baz", "", "TestFoo", "bar", true, true}, - {"/bar/baz", "", "TestFoo", "bar/baz", true, false}, - {"//baz", "", "TestFoo", "bar/baz", true, false}, - {"//", "", "TestFoo", "bar/baz", true, false}, - {"/bar/baz", "", "TestFoo/bar", "baz", true, false}, - {"//foo", "", "TestFoo", "bar/baz", false, false}, - {"/bar/baz", "", "TestFoo", "x", false, false}, - {"/bar/baz", "", "TestBar", "x/bar/baz", false, false}, - } - - for _, tc := range testCases { - m := newMatcher(regexp.MatchString, tc.pattern, "-test.run", tc.skip) - - parent := &common{name: tc.parent} - if tc.parent != "" { - parent.level = 1 - } - if n, ok, partial := m.fullName(parent, tc.sub); ok != tc.ok || partial != tc.partial { - t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v partial %v; want ok %v partial %v", - tc.pattern, tc.parent, tc.sub, n, ok, partial, tc.ok, tc.partial) - } - } -} - -var namingTestCases = []struct{ name, want string }{ - // Uniqueness - {"", "x/#00"}, - {"", "x/#01"}, - {"#0", "x/#0"}, // Doesn't conflict with #00 because the number of digits differs. - {"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix. - {"#", "x/#"}, - {"#", "x/##01"}, - - {"t", "x/t"}, - {"t", "x/t#01"}, - {"t", "x/t#02"}, - {"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest. - - {"a#01", "x/a#01"}, // user has subtest with this name. - {"a", "x/a"}, // doesn't conflict with this name. - {"a", "x/a#02"}, // This string is claimed now, so resume - {"a", "x/a#03"}, // with counting. - {"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix. - - {"b#00", "x/b#00"}, - {"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00". - {"b", "x/b#01"}, - {"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64 - {"b", "x/b#02"}, - {"b", "x/b#03"}, - - // Sanitizing - {"A:1 B:2", "x/A:1_B:2"}, - {"s\t\r\u00a0", "x/s___"}, - {"\x01", `x/\x01`}, - {"\U0010ffff", `x/\U0010ffff`}, -} - -func TestNaming(t *T) { - m := newMatcher(regexp.MatchString, "", "", "") - parent := &common{name: "x", level: 1} // top-level test. - - for i, tc := range namingTestCases { - if got, _, _ := m.fullName(parent, tc.name); got != tc.want { - t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want) - } - } -} - -func FuzzNaming(f *F) { - for _, tc := range namingTestCases { - f.Add(tc.name) - } - parent := &common{name: "x", level: 1} - var m *matcher - var seen map[string]string - reset := func() { - m = allMatcher() - seen = make(map[string]string) - } - reset() - - f.Fuzz(func(t *T, subname string) { - if len(subname) > 10 { - // Long names attract the OOM killer. - t.Skip() - } - name := m.unique(parent.name, subname) - if !strings.Contains(name, "/"+subname) { - t.Errorf("name %q does not contain subname %q", name, subname) - } - if prev, ok := seen[name]; ok { - t.Errorf("name %q generated by both %q and %q", name, prev, subname) - } - if len(seen) > 1e6 { - // Free up memory. - reset() - } - seen[name] = subname - }) -} - -// GoString returns a string that is more readable than the default, which makes -// it easier to read test errors. -func (m alternationMatch) GoString() string { - s := make([]string, len(m)) - for i, m := range m { - s[i] = fmt.Sprintf("%#v", m) - } - return fmt.Sprintf("(%s)", strings.Join(s, " | ")) -} diff --git a/testing/testing/newcover.go b/testing/testing/newcover.go deleted file mode 100644 index 5a8d7288..00000000 --- a/testing/testing/newcover.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2022 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. - -// Support for test coverage with redesigned coverage implementation. - -package testing - -import ( - "fmt" - "os" - _ "unsafe" // for linkname -) - -// cover variable stores the current coverage mode and a -// tear-down function to be called at the end of the testing run. -var cover struct { - mode string - tearDown func(coverprofile string, gocoverdir string) (string, error) - snapshotcov func() float64 -} - -// registerCover is invoked during "go test -cover" runs. -// It is used to record a 'tear down' function -// (to be called when the test is complete) and the coverage mode. -func registerCover(mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { - if mode == "" { - return - } - cover.mode = mode - cover.tearDown = tearDown - cover.snapshotcov = snapcov -} - -// coverReport reports the coverage percentage and -// writes a coverage profile if requested. -// This invokes a callback in _testmain.go that will -// emit coverage data at the point where test execution is complete, -// for "go test -cover" runs. -func coverReport() { - if errmsg, err := cover.tearDown(*coverProfile, *gocoverdir); err != nil { - fmt.Fprintf(os.Stderr, "%s: %v\n", errmsg, err) - os.Exit(2) - } -} - -// Coverage reports the current code coverage as a fraction in the range [0, 1]. -// If coverage is not enabled, Coverage returns 0. -// -// When running a large set of sequential test cases, checking Coverage after each one -// can be useful for identifying which test cases exercise new code paths. -// It is not a replacement for the reports generated by 'go test -cover' and -// 'go tool cover'. -func Coverage() float64 { - if cover.mode == "" { - return 0.0 - } - return cover.snapshotcov() -} diff --git a/testing/testing/panic_test.go b/testing/testing/panic_test.go deleted file mode 100644 index ae53bd92..00000000 --- a/testing/testing/panic_test.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2019 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 ( - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "regexp" - "runtime" - "strings" - "testing" -) - -var testPanicTest = flag.String("test_panic_test", "", "TestPanic: indicates which test should panic") -var testPanicParallel = flag.Bool("test_panic_parallel", false, "TestPanic: run subtests in parallel") -var testPanicCleanup = flag.Bool("test_panic_cleanup", false, "TestPanic: indicates whether test should call Cleanup") -var testPanicCleanupPanic = flag.String("test_panic_cleanup_panic", "", "TestPanic: indicate whether test should call Cleanup function that panics") - -func TestPanic(t *testing.T) { - testenv.MustHaveExec(t) - - testCases := []struct { - desc string - flags []string - want string - }{{ - desc: "root test panics", - flags: []string{"-test_panic_test=TestPanicHelper"}, - want: ` ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper -`, - }, { - desc: "subtest panics", - flags: []string{"-test_panic_test=TestPanicHelper/1"}, - want: ` ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "subtest panics with cleanup", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "subtest panics with outer cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper -`, - }, { - desc: "subtest panics with middle cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "subtest panics with inner cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "parallel subtest panics with cleanup", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_parallel"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "parallel subtest panics with outer cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer", "-test_panic_parallel"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper -`, - }, { - desc: "parallel subtest panics with middle cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle", "-test_panic_parallel"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }, { - desc: "parallel subtest panics with inner cleanup panic", - flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner", "-test_panic_parallel"}, - want: ` -ran inner cleanup 1 -ran middle cleanup 1 -ran outer cleanup ---- FAIL: TestPanicHelper (N.NNs) - panic_test.go:NNN: TestPanicHelper - TestPanicHelper - --- FAIL: TestPanicHelper/1 (N.NNs) - panic_test.go:NNN: TestPanicHelper/1 - TestPanicHelper/1 -`, - }} - for _, tc := range testCases { - t.Run(tc.desc, func(t *testing.T) { - cmd := exec.Command(testenv.Executable(t), "-test.run=^TestPanicHelper$") - cmd.Args = append(cmd.Args, tc.flags...) - cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") - b, _ := cmd.CombinedOutput() - got := string(b) - want := strings.TrimSpace(tc.want) - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want) - } - }) - } -} - -func makeRegexp(s string) string { - s = regexp.QuoteMeta(s) - s = strings.ReplaceAll(s, ":NNN:", `:\d+:`) - s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`) - return s -} - -func TestPanicHelper(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - return - } - t.Log(t.Name()) - t.Output().Write([]byte(t.Name())) - if t.Name() == *testPanicTest { - panic("panic") - } - switch *testPanicCleanupPanic { - case "", "outer", "middle", "inner": - default: - t.Fatalf("bad -test_panic_cleanup_panic: %s", *testPanicCleanupPanic) - } - t.Cleanup(func() { - fmt.Println("ran outer cleanup") - if *testPanicCleanupPanic == "outer" { - panic("outer cleanup") - } - }) - for i := 0; i < 3; i++ { - i := i - t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { - chosen := t.Name() == *testPanicTest - if chosen && *testPanicCleanup { - t.Cleanup(func() { - fmt.Printf("ran middle cleanup %d\n", i) - if *testPanicCleanupPanic == "middle" { - panic("middle cleanup") - } - }) - } - if chosen && *testPanicParallel { - t.Parallel() - } - t.Log(t.Name()) - t.Output().Write([]byte(t.Name())) - if chosen { - if *testPanicCleanup { - t.Cleanup(func() { - fmt.Printf("ran inner cleanup %d\n", i) - if *testPanicCleanupPanic == "inner" { - panic("inner cleanup") - } - }) - } - panic("panic") - } - }) - } -} - -func TestMorePanic(t *testing.T) { - testenv.MustHaveExec(t) - - testCases := []struct { - desc string - flags []string - want string - }{ - { - desc: "Issue 48502: call runtime.Goexit in t.Cleanup after panic", - flags: []string{"-test.run=^TestGoexitInCleanupAfterPanicHelper$"}, - want: `panic: die - panic: test executed panic(nil) or runtime.Goexit`, - }, - { - desc: "Issue 48515: call t.Run in t.Cleanup should trigger panic", - flags: []string{"-test.run=^TestCallRunInCleanupHelper$"}, - want: `panic: testing: t.Run called during t.Cleanup`, - }, - } - - for _, tc := range testCases { - cmd := exec.Command(testenv.Executable(t), tc.flags...) - cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") - b, _ := cmd.CombinedOutput() - got := string(b) - want := tc.want - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want) - } - } -} - -func TestCallRunInCleanupHelper(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - return - } - - t.Cleanup(func() { - t.Run("in-cleanup", func(t *testing.T) { - t.Log("must not be executed") - }) - }) -} - -func TestGoexitInCleanupAfterPanicHelper(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - return - } - - t.Cleanup(func() { runtime.Goexit() }) - t.Parallel() - panic("die") -} diff --git a/testing/testing/quick/quick.go b/testing/testing/quick/quick.go deleted file mode 100644 index 8ef9cf7d..00000000 --- a/testing/testing/quick/quick.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2009 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 quick implements utility functions to help with black box testing. -// -// The testing/quick package is frozen and is not accepting new features. -package quick - -import ( - "flag" - "fmt" - "math" - "math/rand" - "reflect" - "strings" - "time" -) - -var defaultMaxCount *int = flag.Int("quickchecks", 100, "The default number of iterations for each check") - -// A Generator can generate random values of its own type. -type Generator interface { - // Generate returns a random instance of the type on which it is a - // method using the size as a size hint. - Generate(rand *rand.Rand, size int) reflect.Value -} - -// randFloat32 generates a random float taking the full range of a float32. -func randFloat32(rand *rand.Rand) float32 { - f := rand.Float64() * math.MaxFloat32 - if rand.Int()&1 == 1 { - f = -f - } - return float32(f) -} - -// randFloat64 generates a random float taking the full range of a float64. -func randFloat64(rand *rand.Rand) float64 { - f := rand.Float64() * math.MaxFloat64 - if rand.Int()&1 == 1 { - f = -f - } - return f -} - -// randInt64 returns a random int64. -func randInt64(rand *rand.Rand) int64 { - return int64(rand.Uint64()) -} - -// complexSize is the maximum length of arbitrary values that contain other -// values. -const complexSize = 50 - -// Value returns an arbitrary value of the given type. -// If the type implements the [Generator] interface, that will be used. -// Note: To create arbitrary values for structs, all the fields must be exported. -func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { - return sizedValue(t, rand, complexSize) -} - -// sizedValue returns an arbitrary value of the given type. The size -// hint is used for shrinking as a function of indirection level so -// that recursive data structures will terminate. -func sizedValue(t reflect.Type, rand *rand.Rand, size int) (value reflect.Value, ok bool) { - if m, ok := reflect.Zero(t).Interface().(Generator); ok { - return m.Generate(rand, size), true - } - - v := reflect.New(t).Elem() - switch concrete := t; concrete.Kind() { - case reflect.Bool: - v.SetBool(rand.Int()&1 == 0) - case reflect.Float32: - v.SetFloat(float64(randFloat32(rand))) - case reflect.Float64: - v.SetFloat(randFloat64(rand)) - case reflect.Complex64: - v.SetComplex(complex(float64(randFloat32(rand)), float64(randFloat32(rand)))) - case reflect.Complex128: - v.SetComplex(complex(randFloat64(rand), randFloat64(rand))) - case reflect.Int16: - v.SetInt(randInt64(rand)) - case reflect.Int32: - v.SetInt(randInt64(rand)) - case reflect.Int64: - v.SetInt(randInt64(rand)) - case reflect.Int8: - v.SetInt(randInt64(rand)) - case reflect.Int: - v.SetInt(randInt64(rand)) - case reflect.Uint16: - v.SetUint(uint64(randInt64(rand))) - case reflect.Uint32: - v.SetUint(uint64(randInt64(rand))) - case reflect.Uint64: - v.SetUint(uint64(randInt64(rand))) - case reflect.Uint8: - v.SetUint(uint64(randInt64(rand))) - case reflect.Uint: - v.SetUint(uint64(randInt64(rand))) - case reflect.Uintptr: - v.SetUint(uint64(randInt64(rand))) - case reflect.Map: - numElems := rand.Intn(size) - v.Set(reflect.MakeMap(concrete)) - for i := 0; i < numElems; i++ { - key, ok1 := sizedValue(concrete.Key(), rand, size) - value, ok2 := sizedValue(concrete.Elem(), rand, size) - if !ok1 || !ok2 { - return reflect.Value{}, false - } - v.SetMapIndex(key, value) - } - case reflect.Pointer: - if rand.Intn(size) == 0 { - v.SetZero() // Generate nil pointer. - } else { - elem, ok := sizedValue(concrete.Elem(), rand, size) - if !ok { - return reflect.Value{}, false - } - v.Set(reflect.New(concrete.Elem())) - v.Elem().Set(elem) - } - case reflect.Slice: - numElems := rand.Intn(size) - sizeLeft := size - numElems - v.Set(reflect.MakeSlice(concrete, numElems, numElems)) - for i := 0; i < numElems; i++ { - elem, ok := sizedValue(concrete.Elem(), rand, sizeLeft) - if !ok { - return reflect.Value{}, false - } - v.Index(i).Set(elem) - } - case reflect.Array: - for i := 0; i < v.Len(); i++ { - elem, ok := sizedValue(concrete.Elem(), rand, size) - if !ok { - return reflect.Value{}, false - } - v.Index(i).Set(elem) - } - case reflect.String: - numChars := rand.Intn(complexSize) - codePoints := make([]rune, numChars) - for i := 0; i < numChars; i++ { - codePoints[i] = rune(rand.Intn(0x10ffff)) - } - v.SetString(string(codePoints)) - case reflect.Struct: - n := v.NumField() - // Divide sizeLeft evenly among the struct fields. - sizeLeft := size - if n > sizeLeft { - sizeLeft = 1 - } else if n > 0 { - sizeLeft /= n - } - for i := 0; i < n; i++ { - elem, ok := sizedValue(concrete.Field(i).Type, rand, sizeLeft) - if !ok { - return reflect.Value{}, false - } - v.Field(i).Set(elem) - } - default: - return reflect.Value{}, false - } - - return v, true -} - -// A Config structure contains options for running a test. -type Config struct { - // MaxCount sets the maximum number of iterations. - // If zero, MaxCountScale is used. - MaxCount int - // MaxCountScale is a non-negative scale factor applied to the - // default maximum. - // A count of zero implies the default, which is usually 100 - // but can be set by the -quickchecks flag. - MaxCountScale float64 - // Rand specifies a source of random numbers. - // If nil, a default pseudo-random source will be used. - Rand *rand.Rand - // Values specifies a function to generate a slice of - // arbitrary reflect.Values that are congruent with the - // arguments to the function being tested. - // If nil, the top-level Value function is used to generate them. - Values func([]reflect.Value, *rand.Rand) -} - -var defaultConfig Config - -// getRand returns the *rand.Rand to use for a given Config. -func (c *Config) getRand() *rand.Rand { - if c.Rand == nil { - return rand.New(rand.NewSource(time.Now().UnixNano())) - } - return c.Rand -} - -// getMaxCount returns the maximum number of iterations to run for a given -// Config. -func (c *Config) getMaxCount() (maxCount int) { - maxCount = c.MaxCount - if maxCount == 0 { - if c.MaxCountScale != 0 { - maxCount = int(c.MaxCountScale * float64(*defaultMaxCount)) - } else { - maxCount = *defaultMaxCount - } - } - - return -} - -// A SetupError is the result of an error in the way that check is being -// used, independent of the functions being tested. -type SetupError string - -func (s SetupError) Error() string { return string(s) } - -// A CheckError is the result of Check finding an error. -type CheckError struct { - Count int - In []any -} - -func (s *CheckError) Error() string { - return fmt.Sprintf("#%d: failed on input %s", s.Count, toString(s.In)) -} - -// A CheckEqualError is the result [CheckEqual] finding an error. -type CheckEqualError struct { - CheckError - Out1 []any - Out2 []any -} - -func (s *CheckEqualError) Error() string { - return fmt.Sprintf("#%d: failed on input %s. Output 1: %s. Output 2: %s", s.Count, toString(s.In), toString(s.Out1), toString(s.Out2)) -} - -// Check looks for an input to f, any function that returns bool, -// such that f returns false. It calls f repeatedly, with arbitrary -// values for each argument. If f returns false on a given input, -// Check returns that input as a *[CheckError]. -// For example: -// -// func TestOddMultipleOfThree(t *testing.T) { -// f := func(x int) bool { -// y := OddMultipleOfThree(x) -// return y%2 == 1 && y%3 == 0 -// } -// if err := quick.Check(f, nil); err != nil { -// t.Error(err) -// } -// } -func Check(f any, config *Config) error { - if config == nil { - config = &defaultConfig - } - - fVal, fType, ok := functionAndType(f) - if !ok { - return SetupError("argument is not a function") - } - - if fType.NumOut() != 1 { - return SetupError("function does not return one value") - } - if fType.Out(0).Kind() != reflect.Bool { - return SetupError("function does not return a bool") - } - - arguments := make([]reflect.Value, fType.NumIn()) - rand := config.getRand() - maxCount := config.getMaxCount() - - for i := 0; i < maxCount; i++ { - err := arbitraryValues(arguments, fType, config, rand) - if err != nil { - return err - } - - if !fVal.Call(arguments)[0].Bool() { - return &CheckError{i + 1, toInterfaces(arguments)} - } - } - - return nil -} - -// CheckEqual looks for an input on which f and g return different results. -// It calls f and g repeatedly with arbitrary values for each argument. -// If f and g return different answers, CheckEqual returns a *[CheckEqualError] -// describing the input and the outputs. -func CheckEqual(f, g any, config *Config) error { - if config == nil { - config = &defaultConfig - } - - x, xType, ok := functionAndType(f) - if !ok { - return SetupError("f is not a function") - } - y, yType, ok := functionAndType(g) - if !ok { - return SetupError("g is not a function") - } - - if xType != yType { - return SetupError("functions have different types") - } - - arguments := make([]reflect.Value, xType.NumIn()) - rand := config.getRand() - maxCount := config.getMaxCount() - - for i := 0; i < maxCount; i++ { - err := arbitraryValues(arguments, xType, config, rand) - if err != nil { - return err - } - - xOut := toInterfaces(x.Call(arguments)) - yOut := toInterfaces(y.Call(arguments)) - - if !reflect.DeepEqual(xOut, yOut) { - return &CheckEqualError{CheckError{i + 1, toInterfaces(arguments)}, xOut, yOut} - } - } - - return nil -} - -// arbitraryValues writes Values to args such that args contains Values -// suitable for calling f. -func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err error) { - if config.Values != nil { - config.Values(args, rand) - return - } - - for j := 0; j < len(args); j++ { - var ok bool - args[j], ok = Value(f.In(j), rand) - if !ok { - err = SetupError(fmt.Sprintf("cannot create arbitrary value of type %s for argument %d", f.In(j), j)) - return - } - } - - return -} - -func functionAndType(f any) (v reflect.Value, t reflect.Type, ok bool) { - v = reflect.ValueOf(f) - ok = v.Kind() == reflect.Func - if !ok { - return - } - t = v.Type() - return -} - -func toInterfaces(values []reflect.Value) []any { - ret := make([]any, len(values)) - for i, v := range values { - ret[i] = v.Interface() - } - return ret -} - -func toString(interfaces []any) string { - s := make([]string, len(interfaces)) - for i, v := range interfaces { - s[i] = fmt.Sprintf("%#v", v) - } - return strings.Join(s, ", ") -} diff --git a/testing/testing/quick/quick_test.go b/testing/testing/quick/quick_test.go deleted file mode 100644 index 9df6dd46..00000000 --- a/testing/testing/quick/quick_test.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2009 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 quick - -import ( - "math/rand" - "reflect" - "testing" -) - -func fArray(a [4]byte) [4]byte { return a } - -type TestArrayAlias [4]byte - -func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a } - -func fBool(a bool) bool { return a } - -type TestBoolAlias bool - -func fBoolAlias(a TestBoolAlias) TestBoolAlias { return a } - -func fFloat32(a float32) float32 { return a } - -type TestFloat32Alias float32 - -func fFloat32Alias(a TestFloat32Alias) TestFloat32Alias { return a } - -func fFloat64(a float64) float64 { return a } - -type TestFloat64Alias float64 - -func fFloat64Alias(a TestFloat64Alias) TestFloat64Alias { return a } - -func fComplex64(a complex64) complex64 { return a } - -type TestComplex64Alias complex64 - -func fComplex64Alias(a TestComplex64Alias) TestComplex64Alias { return a } - -func fComplex128(a complex128) complex128 { return a } - -type TestComplex128Alias complex128 - -func fComplex128Alias(a TestComplex128Alias) TestComplex128Alias { return a } - -func fInt16(a int16) int16 { return a } - -type TestInt16Alias int16 - -func fInt16Alias(a TestInt16Alias) TestInt16Alias { return a } - -func fInt32(a int32) int32 { return a } - -type TestInt32Alias int32 - -func fInt32Alias(a TestInt32Alias) TestInt32Alias { return a } - -func fInt64(a int64) int64 { return a } - -type TestInt64Alias int64 - -func fInt64Alias(a TestInt64Alias) TestInt64Alias { return a } - -func fInt8(a int8) int8 { return a } - -type TestInt8Alias int8 - -func fInt8Alias(a TestInt8Alias) TestInt8Alias { return a } - -func fInt(a int) int { return a } - -type TestIntAlias int - -func fIntAlias(a TestIntAlias) TestIntAlias { return a } - -func fMap(a map[int]int) map[int]int { return a } - -type TestMapAlias map[int]int - -func fMapAlias(a TestMapAlias) TestMapAlias { return a } - -func fPtr(a *int) *int { - if a == nil { - return nil - } - b := *a - return &b -} - -type TestPtrAlias *int - -func fPtrAlias(a TestPtrAlias) TestPtrAlias { return a } - -func fSlice(a []byte) []byte { return a } - -type TestSliceAlias []byte - -func fSliceAlias(a TestSliceAlias) TestSliceAlias { return a } - -func fString(a string) string { return a } - -type TestStringAlias string - -func fStringAlias(a TestStringAlias) TestStringAlias { return a } - -type TestStruct struct { - A int - B string -} - -func fStruct(a TestStruct) TestStruct { return a } - -type TestStructAlias TestStruct - -func fStructAlias(a TestStructAlias) TestStructAlias { return a } - -func fUint16(a uint16) uint16 { return a } - -type TestUint16Alias uint16 - -func fUint16Alias(a TestUint16Alias) TestUint16Alias { return a } - -func fUint32(a uint32) uint32 { return a } - -type TestUint32Alias uint32 - -func fUint32Alias(a TestUint32Alias) TestUint32Alias { return a } - -func fUint64(a uint64) uint64 { return a } - -type TestUint64Alias uint64 - -func fUint64Alias(a TestUint64Alias) TestUint64Alias { return a } - -func fUint8(a uint8) uint8 { return a } - -type TestUint8Alias uint8 - -func fUint8Alias(a TestUint8Alias) TestUint8Alias { return a } - -func fUint(a uint) uint { return a } - -type TestUintAlias uint - -func fUintAlias(a TestUintAlias) TestUintAlias { return a } - -func fUintptr(a uintptr) uintptr { return a } - -type TestUintptrAlias uintptr - -func fUintptrAlias(a TestUintptrAlias) TestUintptrAlias { return a } - -func reportError(property string, err error, t *testing.T) { - if err != nil { - t.Errorf("%s: %s", property, err) - } -} - -func TestCheckEqual(t *testing.T) { - reportError("fArray", CheckEqual(fArray, fArray, nil), t) - reportError("fArrayAlias", CheckEqual(fArrayAlias, fArrayAlias, nil), t) - reportError("fBool", CheckEqual(fBool, fBool, nil), t) - reportError("fBoolAlias", CheckEqual(fBoolAlias, fBoolAlias, nil), t) - reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t) - reportError("fFloat32Alias", CheckEqual(fFloat32Alias, fFloat32Alias, nil), t) - reportError("fFloat64", CheckEqual(fFloat64, fFloat64, nil), t) - reportError("fFloat64Alias", CheckEqual(fFloat64Alias, fFloat64Alias, nil), t) - reportError("fComplex64", CheckEqual(fComplex64, fComplex64, nil), t) - reportError("fComplex64Alias", CheckEqual(fComplex64Alias, fComplex64Alias, nil), t) - reportError("fComplex128", CheckEqual(fComplex128, fComplex128, nil), t) - reportError("fComplex128Alias", CheckEqual(fComplex128Alias, fComplex128Alias, nil), t) - reportError("fInt16", CheckEqual(fInt16, fInt16, nil), t) - reportError("fInt16Alias", CheckEqual(fInt16Alias, fInt16Alias, nil), t) - reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t) - reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t) - reportError("fInt64", CheckEqual(fInt64, fInt64, nil), t) - reportError("fInt64Alias", CheckEqual(fInt64Alias, fInt64Alias, nil), t) - reportError("fInt8", CheckEqual(fInt8, fInt8, nil), t) - reportError("fInt8Alias", CheckEqual(fInt8Alias, fInt8Alias, nil), t) - reportError("fInt", CheckEqual(fInt, fInt, nil), t) - reportError("fIntAlias", CheckEqual(fIntAlias, fIntAlias, nil), t) - reportError("fInt32", CheckEqual(fInt32, fInt32, nil), t) - reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t) - reportError("fMap", CheckEqual(fMap, fMap, nil), t) - reportError("fMapAlias", CheckEqual(fMapAlias, fMapAlias, nil), t) - reportError("fPtr", CheckEqual(fPtr, fPtr, nil), t) - reportError("fPtrAlias", CheckEqual(fPtrAlias, fPtrAlias, nil), t) - reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t) - reportError("fSliceAlias", CheckEqual(fSliceAlias, fSliceAlias, nil), t) - reportError("fString", CheckEqual(fString, fString, nil), t) - reportError("fStringAlias", CheckEqual(fStringAlias, fStringAlias, nil), t) - reportError("fStruct", CheckEqual(fStruct, fStruct, nil), t) - reportError("fStructAlias", CheckEqual(fStructAlias, fStructAlias, nil), t) - reportError("fUint16", CheckEqual(fUint16, fUint16, nil), t) - reportError("fUint16Alias", CheckEqual(fUint16Alias, fUint16Alias, nil), t) - reportError("fUint32", CheckEqual(fUint32, fUint32, nil), t) - reportError("fUint32Alias", CheckEqual(fUint32Alias, fUint32Alias, nil), t) - reportError("fUint64", CheckEqual(fUint64, fUint64, nil), t) - reportError("fUint64Alias", CheckEqual(fUint64Alias, fUint64Alias, nil), t) - reportError("fUint8", CheckEqual(fUint8, fUint8, nil), t) - reportError("fUint8Alias", CheckEqual(fUint8Alias, fUint8Alias, nil), t) - reportError("fUint", CheckEqual(fUint, fUint, nil), t) - reportError("fUintAlias", CheckEqual(fUintAlias, fUintAlias, nil), t) - reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t) - reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t) -} - -// This tests that ArbitraryValue is working by checking that all the arbitrary -// values of type MyStruct have x = 42. -type myStruct struct { - x int -} - -func (m myStruct) Generate(r *rand.Rand, _ int) reflect.Value { - return reflect.ValueOf(myStruct{x: 42}) -} - -func myStructProperty(in myStruct) bool { return in.x == 42 } - -func TestCheckProperty(t *testing.T) { - reportError("myStructProperty", Check(myStructProperty, nil), t) -} - -func TestFailure(t *testing.T) { - f := func(x int) bool { return false } - err := Check(f, nil) - if err == nil { - t.Errorf("Check didn't return an error") - } - if _, ok := err.(*CheckError); !ok { - t.Errorf("Error was not a CheckError: %s", err) - } - - err = CheckEqual(fUint, fUint32, nil) - if err == nil { - t.Errorf("#1 CheckEqual didn't return an error") - } - if _, ok := err.(SetupError); !ok { - t.Errorf("#1 Error was not a SetupError: %s", err) - } - - err = CheckEqual(func(x, y int) {}, func(x int) {}, nil) - if err == nil { - t.Errorf("#2 CheckEqual didn't return an error") - } - if _, ok := err.(SetupError); !ok { - t.Errorf("#2 Error was not a SetupError: %s", err) - } - - err = CheckEqual(func(x int) int { return 0 }, func(x int) int32 { return 0 }, nil) - if err == nil { - t.Errorf("#3 CheckEqual didn't return an error") - } - if _, ok := err.(SetupError); !ok { - t.Errorf("#3 Error was not a SetupError: %s", err) - } -} - -// Recursive data structures didn't terminate. -// Issues 8818 and 11148. -func TestRecursive(t *testing.T) { - type R struct { - Ptr *R - SliceP []*R - Slice []R - Map map[int]R - MapP map[int]*R - MapR map[*R]*R - SliceMap []map[int]R - } - - f := func(r R) bool { return true } - Check(f, nil) -} - -func TestEmptyStruct(t *testing.T) { - f := func(struct{}) bool { return true } - Check(f, nil) -} - -type ( - A struct{ B *B } - B struct{ A *A } -) - -func TestMutuallyRecursive(t *testing.T) { - f := func(a A) bool { return true } - Check(f, nil) -} - -// Some serialization formats (e.g. encoding/pem) cannot distinguish -// between a nil and an empty map or slice, so avoid generating the -// zero value for these. -func TestNonZeroSliceAndMap(t *testing.T) { - type Q struct { - M map[int]int - S []int - } - f := func(q Q) bool { - return q.M != nil && q.S != nil - } - err := Check(f, nil) - if err != nil { - t.Fatal(err) - } -} - -func TestInt64(t *testing.T) { - var lo, hi int64 - f := func(x int64) bool { - if x < lo { - lo = x - } - if x > hi { - hi = x - } - return true - } - cfg := &Config{MaxCount: 10000} - Check(f, cfg) - if uint64(lo)>>62 == 0 || uint64(hi)>>62 == 0 { - t.Errorf("int64 returned range %#016x,%#016x; does not look like full range", lo, hi) - } -} diff --git a/testing/testing/run_example.go b/testing/testing/run_example.go deleted file mode 100644 index b2c5c3d1..00000000 --- a/testing/testing/run_example.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 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 !js && !wasip1 - -// TODO(@musiol, @odeke-em): re-unify this entire file back into -// example.go when js/wasm gets an os.Pipe implementation -// and no longer needs this separation. - -package testing - -import ( - "fmt" - "io" - "os" - "strings" - "time" -) - -func runExample(eg InternalExample) (ok bool) { - if chatty.on { - fmt.Printf("%s=== RUN %s\n", chatty.prefix(), eg.Name) - } - - // Capture stdout. - stdout := os.Stdout - r, w, err := os.Pipe() - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - os.Stdout = w - outC := make(chan string) - go func() { - var buf strings.Builder - _, err := io.Copy(&buf, r) - r.Close() - if err != nil { - fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err) - os.Exit(1) - } - outC <- buf.String() - }() - - finished := false - start := time.Now() - - // Clean up in a deferred call so we can recover if the example panics. - defer func() { - timeSpent := time.Since(start) - - // Close pipe, restore stdout, get output. - w.Close() - os.Stdout = stdout - out := <-outC - - err := recover() - ok = eg.processRunResult(out, timeSpent, finished, err) - }() - - // Run example. - eg.F() - finished = true - return -} diff --git a/testing/testing/run_example_wasm.go b/testing/testing/run_example_wasm.go deleted file mode 100644 index b815fcdb..00000000 --- a/testing/testing/run_example_wasm.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 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 js || wasip1 - -package testing - -import ( - "fmt" - "io" - "os" - "strings" - "time" -) - -// TODO(@musiol, @odeke-em): unify this code back into -// example.go when js/wasm gets an os.Pipe implementation. -func runExample(eg InternalExample) (ok bool) { - if chatty.on { - fmt.Printf("%s=== RUN %s\n", chatty.prefix(), eg.Name) - } - - // Capture stdout to temporary file. We're not using - // os.Pipe because it is not supported on js/wasm. - stdout := os.Stdout - f := createTempFile(eg.Name) - os.Stdout = f - finished := false - start := time.Now() - - // Clean up in a deferred call so we can recover if the example panics. - defer func() { - timeSpent := time.Since(start) - - // Restore stdout, get output and remove temporary file. - os.Stdout = stdout - var buf strings.Builder - _, seekErr := f.Seek(0, io.SeekStart) - _, readErr := io.Copy(&buf, f) - out := buf.String() - f.Close() - os.Remove(f.Name()) - if seekErr != nil { - fmt.Fprintf(os.Stderr, "testing: seek temp file: %v\n", seekErr) - os.Exit(1) - } - if readErr != nil { - fmt.Fprintf(os.Stderr, "testing: read temp file: %v\n", readErr) - os.Exit(1) - } - - err := recover() - ok = eg.processRunResult(out, timeSpent, finished, err) - }() - - // Run example. - eg.F() - finished = true - return -} - -func createTempFile(exampleName string) *os.File { - for i := 0; ; i++ { - name := fmt.Sprintf("%s/go-example-stdout-%s-%d.txt", os.TempDir(), exampleName, i) - f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) - if err != nil { - if os.IsExist(err) { - continue - } - fmt.Fprintf(os.Stderr, "testing: open temp file: %v\n", err) - os.Exit(1) - } - return f - } -} diff --git a/testing/testing/slogtest/example_test.go b/testing/testing/slogtest/example_test.go deleted file mode 100644 index 88fd2427..00000000 --- a/testing/testing/slogtest/example_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2023 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 slogtest_test - -import ( - "bytes" - "encoding/json" - "log" - "log/slog" - "testing/slogtest" -) - -// This example demonstrates one technique for testing a handler with this -// package. The handler is given a [bytes.Buffer] to write to, and each line -// of the resulting output is parsed. -// For JSON output, [encoding/json.Unmarshal] produces a result in the desired -// format when given a pointer to a map[string]any. -func Example_parsing() { - var buf bytes.Buffer - h := slog.NewJSONHandler(&buf, nil) - - results := func() []map[string]any { - var ms []map[string]any - for line := range bytes.SplitSeq(buf.Bytes(), []byte{'\n'}) { - if len(line) == 0 { - continue - } - var m map[string]any - if err := json.Unmarshal(line, &m); err != nil { - panic(err) // In a real test, use t.Fatal. - } - ms = append(ms, m) - } - return ms - } - err := slogtest.TestHandler(h, results) - if err != nil { - log.Fatal(err) - } - - // Output: -} diff --git a/testing/testing/slogtest/run_test.go b/testing/testing/slogtest/run_test.go deleted file mode 100644 index c82da10c..00000000 --- a/testing/testing/slogtest/run_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2023 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 slogtest_test - -import ( - "bytes" - "encoding/json" - "log/slog" - "testing" - "testing/slogtest" -) - -func TestRun(t *testing.T) { - var buf bytes.Buffer - - newHandler := func(*testing.T) slog.Handler { - buf.Reset() - return slog.NewJSONHandler(&buf, nil) - } - result := func(t *testing.T) map[string]any { - m := map[string]any{} - if err := json.Unmarshal(buf.Bytes(), &m); err != nil { - t.Fatal(err) - } - return m - } - - slogtest.Run(t, newHandler, result) -} diff --git a/testing/testing/slogtest/slogtest.go b/testing/testing/slogtest/slogtest.go deleted file mode 100644 index 651d1d37..00000000 --- a/testing/testing/slogtest/slogtest.go +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright 2023 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 slogtest implements support for testing implementations of log/slog.Handler. -package slogtest - -import ( - "context" - "errors" - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "log/slog" - "reflect" - "runtime" - "time" -) - -type testCase struct { - // Subtest name. - name string - // If non-empty, explanation explains the violated constraint. - explanation string - // f executes a single log event using its argument logger. - // So that mkdescs.sh can generate the right description, - // the body of f must appear on a single line whose first - // non-whitespace characters are "l.". - f func(*slog.Logger) - // If mod is not nil, it is called to modify the Record - // generated by the Logger before it is passed to the Handler. - mod func(*slog.Record) - // checks is a list of checks to run on the result. - checks []check -} - -var cases = []testCase{ - { - name: "built-ins", - explanation: withSource("this test expects slog.TimeKey, slog.LevelKey and slog.MessageKey"), - f: func(l *slog.Logger) { - l.Info("message") - }, - checks: []check{ - hasKey(slog.TimeKey), - hasKey(slog.LevelKey), - hasAttr(slog.MessageKey, "message"), - }, - }, - { - name: "attrs", - explanation: withSource("a Handler should output attributes passed to the logging function"), - f: func(l *slog.Logger) { - l.Info("message", "k", "v") - }, - checks: []check{ - hasAttr("k", "v"), - }, - }, - { - name: "empty-attr", - explanation: withSource("a Handler should ignore an empty Attr"), - f: func(l *slog.Logger) { - l.Info("msg", "a", "b", "", nil, "c", "d") - }, - checks: []check{ - hasAttr("a", "b"), - missingKey(""), - hasAttr("c", "d"), - }, - }, - { - name: "zero-time", - explanation: withSource("a Handler should ignore a zero Record.Time"), - f: func(l *slog.Logger) { - l.Info("msg", "k", "v") - }, - mod: func(r *slog.Record) { r.Time = time.Time{} }, - checks: []check{ - missingKey(slog.TimeKey), - }, - }, - { - name: "WithAttrs", - explanation: withSource("a Handler should include the attributes from the WithAttrs method"), - f: func(l *slog.Logger) { - l.With("a", "b").Info("msg", "k", "v") - }, - checks: []check{ - hasAttr("a", "b"), - hasAttr("k", "v"), - }, - }, - { - name: "groups", - explanation: withSource("a Handler should handle Group attributes"), - f: func(l *slog.Logger) { - l.Info("msg", "a", "b", slog.Group("G", slog.String("c", "d")), "e", "f") - }, - checks: []check{ - hasAttr("a", "b"), - inGroup("G", hasAttr("c", "d")), - hasAttr("e", "f"), - }, - }, - { - name: "empty-group", - explanation: withSource("a Handler should ignore an empty group"), - f: func(l *slog.Logger) { - l.Info("msg", "a", "b", slog.Group("G"), "e", "f") - }, - checks: []check{ - hasAttr("a", "b"), - missingKey("G"), - hasAttr("e", "f"), - }, - }, - { - name: "inline-group", - explanation: withSource("a Handler should inline the Attrs of a group with an empty key"), - f: func(l *slog.Logger) { - l.Info("msg", "a", "b", slog.Group("", slog.String("c", "d")), "e", "f") - - }, - checks: []check{ - hasAttr("a", "b"), - hasAttr("c", "d"), - hasAttr("e", "f"), - }, - }, - { - name: "WithGroup", - explanation: withSource("a Handler should handle the WithGroup method"), - f: func(l *slog.Logger) { - l.WithGroup("G").Info("msg", "a", "b") - }, - checks: []check{ - hasKey(slog.TimeKey), - hasKey(slog.LevelKey), - hasAttr(slog.MessageKey, "msg"), - missingKey("a"), - inGroup("G", hasAttr("a", "b")), - }, - }, - { - name: "multi-With", - explanation: withSource("a Handler should handle multiple WithGroup and WithAttr calls"), - f: func(l *slog.Logger) { - l.With("a", "b").WithGroup("G").With("c", "d").WithGroup("H").Info("msg", "e", "f") - }, - checks: []check{ - hasKey(slog.TimeKey), - hasKey(slog.LevelKey), - hasAttr(slog.MessageKey, "msg"), - hasAttr("a", "b"), - inGroup("G", hasAttr("c", "d")), - inGroup("G", inGroup("H", hasAttr("e", "f"))), - }, - }, - { - name: "empty-group-record", - explanation: withSource("a Handler should not output groups if there are no attributes"), - f: func(l *slog.Logger) { - l.With("a", "b").WithGroup("G").With("c", "d").WithGroup("H").Info("msg") - }, - checks: []check{ - hasKey(slog.TimeKey), - hasKey(slog.LevelKey), - hasAttr(slog.MessageKey, "msg"), - hasAttr("a", "b"), - inGroup("G", hasAttr("c", "d")), - inGroup("G", missingKey("H")), - }, - }, - { - name: "nested-empty-group-record", - explanation: withSource("a Handler should not output nested groups if there are no attributes"), - f: func(l *slog.Logger) { - l.With("a", "b").WithGroup("G").With("c", "d").WithGroup("H").WithGroup("I").Info("msg") - }, - checks: []check{ - hasKey(slog.TimeKey), - hasKey(slog.LevelKey), - hasAttr(slog.MessageKey, "msg"), - hasAttr("a", "b"), - inGroup("G", hasAttr("c", "d")), - inGroup("G", missingKey("H")), - inGroup("G", missingKey("I")), - }, - }, - { - name: "resolve", - explanation: withSource("a Handler should call Resolve on attribute values"), - f: func(l *slog.Logger) { - l.Info("msg", "k", &replace{"replaced"}) - }, - checks: []check{hasAttr("k", "replaced")}, - }, - { - name: "resolve-groups", - explanation: withSource("a Handler should call Resolve on attribute values in groups"), - f: func(l *slog.Logger) { - l.Info("msg", - slog.Group("G", - slog.String("a", "v1"), - slog.Any("b", &replace{"v2"}))) - }, - checks: []check{ - inGroup("G", hasAttr("a", "v1")), - inGroup("G", hasAttr("b", "v2")), - }, - }, - { - name: "resolve-WithAttrs", - explanation: withSource("a Handler should call Resolve on attribute values from WithAttrs"), - f: func(l *slog.Logger) { - l = l.With("k", &replace{"replaced"}) - l.Info("msg") - }, - checks: []check{hasAttr("k", "replaced")}, - }, - { - name: "resolve-WithAttrs-groups", - explanation: withSource("a Handler should call Resolve on attribute values in groups from WithAttrs"), - f: func(l *slog.Logger) { - l = l.With(slog.Group("G", - slog.String("a", "v1"), - slog.Any("b", &replace{"v2"}))) - l.Info("msg") - }, - checks: []check{ - inGroup("G", hasAttr("a", "v1")), - inGroup("G", hasAttr("b", "v2")), - }, - }, - { - name: "empty-PC", - explanation: withSource("a Handler should not output SourceKey if the PC is zero"), - f: func(l *slog.Logger) { - l.Info("message") - }, - mod: func(r *slog.Record) { r.PC = 0 }, - checks: []check{ - missingKey(slog.SourceKey), - }, - }, -} - -// TestHandler tests a [slog.Handler]. -// If TestHandler finds any misbehaviors, it returns an error for each, -// combined into a single error with [errors.Join]. -// -// TestHandler installs the given Handler in a [slog.Logger] and -// makes several calls to the Logger's output methods. -// The Handler should be enabled for levels Info and above. -// -// The results function is invoked after all such calls. -// It should return a slice of map[string]any, one for each call to a Logger output method. -// The keys and values of the map should correspond to the keys and values of the Handler's -// output. Each group in the output should be represented as its own nested map[string]any. -// The standard keys [slog.TimeKey], [slog.LevelKey] and [slog.MessageKey] should be used. -// -// If the Handler outputs JSON, then calling [encoding/json.Unmarshal] with a `map[string]any` -// will create the right data structure. -// -// If a Handler intentionally drops an attribute that is checked by a test, -// then the results function should check for its absence and add it to the map it returns. -func TestHandler(h slog.Handler, results func() []map[string]any) error { - // Run the handler on the test cases. - for _, c := range cases { - ht := h - if c.mod != nil { - ht = &wrapper{h, c.mod} - } - l := slog.New(ht) - c.f(l) - } - - // Collect and check the results. - var errs []error - res := results() - if g, w := len(res), len(cases); g != w { - return fmt.Errorf("got %d results, want %d", g, w) - } - for i, got := range res { - c := cases[i] - for _, check := range c.checks { - if problem := check(got); problem != "" { - errs = append(errs, fmt.Errorf("%s: %s", problem, c.explanation)) - } - } - } - return errors.Join(errs...) -} - -// Run exercises a [slog.Handler] on the same test cases as [TestHandler], but -// runs each case in a subtest. For each test case, it first calls newHandler to -// get an instance of the handler under test, then runs the test case, then -// calls result to get the result. If the test case fails, it calls t.Error. -func Run(t *testing.T, newHandler func(*testing.T) slog.Handler, result func(*testing.T) map[string]any) { - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - h := newHandler(t) - if c.mod != nil { - h = &wrapper{h, c.mod} - } - l := slog.New(h) - c.f(l) - got := result(t) - for _, check := range c.checks { - if p := check(got); p != "" { - t.Errorf("%s: %s", p, c.explanation) - } - } - }) - } -} - -type check func(map[string]any) string - -func hasKey(key string) check { - return func(m map[string]any) string { - if _, ok := m[key]; !ok { - return fmt.Sprintf("missing key %q", key) - } - return "" - } -} - -func missingKey(key string) check { - return func(m map[string]any) string { - if _, ok := m[key]; ok { - return fmt.Sprintf("unexpected key %q", key) - } - return "" - } -} - -func hasAttr(key string, wantVal any) check { - return func(m map[string]any) string { - if s := hasKey(key)(m); s != "" { - return s - } - gotVal := m[key] - if !reflect.DeepEqual(gotVal, wantVal) { - return fmt.Sprintf("%q: got %#v, want %#v", key, gotVal, wantVal) - } - return "" - } -} - -func inGroup(name string, c check) check { - return func(m map[string]any) string { - v, ok := m[name] - if !ok { - return fmt.Sprintf("missing group %q", name) - } - g, ok := v.(map[string]any) - if !ok { - return fmt.Sprintf("value for group %q is not map[string]any", name) - } - return c(g) - } -} - -type wrapper struct { - slog.Handler - mod func(*slog.Record) -} - -func (h *wrapper) Handle(ctx context.Context, r slog.Record) error { - h.mod(&r) - return h.Handler.Handle(ctx, r) -} - -func withSource(s string) string { - _, file, line, ok := runtime.Caller(1) - if !ok { - panic("runtime.Caller failed") - } - return fmt.Sprintf("%s (%s:%d)", s, file, line) -} - -type replace struct { - v any -} - -func (r *replace) LogValue() slog.Value { return slog.AnyValue(r.v) } - -func (r *replace) String() string { - return fmt.Sprintf("", r.v) -} diff --git a/testing/testing/sub_test.go b/testing/testing/sub_test.go deleted file mode 100644 index bb5586d9..00000000 --- a/testing/testing/sub_test.go +++ /dev/null @@ -1,1268 +0,0 @@ -// 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 testing - -import ( - "bytes" - "fmt" - "regexp" - "runtime" - "slices" - "strings" - "sync" - "sync/atomic" - "time" -) - -func init() { - // Make benchmark tests run 10x faster. - benchTime.d = 100 * time.Millisecond -} - -func TestTestState(t *T) { - const ( - add1 = 0 - done = 1 - ) - type call struct { - typ int // run or done - // result from applying the call - running int - waiting int - started bool - } - testCases := []struct { - max int - run []call - }{{ - max: 1, - run: []call{ - {typ: add1, running: 1, waiting: 0, started: true}, - {typ: done, running: 0, waiting: 0, started: false}, - }, - }, { - max: 1, - run: []call{ - {typ: add1, running: 1, waiting: 0, started: true}, - {typ: add1, running: 1, waiting: 1, started: false}, - {typ: done, running: 1, waiting: 0, started: true}, - {typ: done, running: 0, waiting: 0, started: false}, - {typ: add1, running: 1, waiting: 0, started: true}, - }, - }, { - max: 3, - run: []call{ - {typ: add1, running: 1, waiting: 0, started: true}, - {typ: add1, running: 2, waiting: 0, started: true}, - {typ: add1, running: 3, waiting: 0, started: true}, - {typ: add1, running: 3, waiting: 1, started: false}, - {typ: add1, running: 3, waiting: 2, started: false}, - {typ: add1, running: 3, waiting: 3, started: false}, - {typ: done, running: 3, waiting: 2, started: true}, - {typ: add1, running: 3, waiting: 3, started: false}, - {typ: done, running: 3, waiting: 2, started: true}, - {typ: done, running: 3, waiting: 1, started: true}, - {typ: done, running: 3, waiting: 0, started: true}, - {typ: done, running: 2, waiting: 0, started: false}, - {typ: done, running: 1, waiting: 0, started: false}, - {typ: done, running: 0, waiting: 0, started: false}, - }, - }} - for i, tc := range testCases { - tstate := &testState{ - startParallel: make(chan bool), - maxParallel: tc.max, - } - for j, call := range tc.run { - doCall := func(f func()) chan bool { - done := make(chan bool) - go func() { - f() - done <- true - }() - return done - } - started := false - switch call.typ { - case add1: - signal := doCall(tstate.waitParallel) - select { - case <-signal: - started = true - case tstate.startParallel <- true: - <-signal - } - case done: - signal := doCall(tstate.release) - select { - case <-signal: - case <-tstate.startParallel: - started = true - <-signal - } - } - if started != call.started { - t.Errorf("%d:%d:started: got %v; want %v", i, j, started, call.started) - } - if tstate.running != call.running { - t.Errorf("%d:%d:running: got %v; want %v", i, j, tstate.running, call.running) - } - if tstate.numWaiting != call.waiting { - t.Errorf("%d:%d:waiting: got %v; want %v", i, j, tstate.numWaiting, call.waiting) - } - } - } -} - -func TestTRun(t *T) { - realTest := t - testCases := []struct { - desc string - ok bool - maxPar int - chatty bool - json bool - output string - f func(*T) - }{{ - desc: "failnow skips future sequential and parallel tests at same level", - ok: false, - maxPar: 1, - output: ` ---- FAIL: failnow skips future sequential and parallel tests at same level (N.NNs) - --- FAIL: failnow skips future sequential and parallel tests at same level/#00 (N.NNs) - `, - f: func(t *T) { - ranSeq := false - ranPar := false - t.Run("", func(t *T) { - t.Run("par", func(t *T) { - t.Parallel() - ranPar = true - }) - t.Run("seq", func(t *T) { - ranSeq = true - }) - t.FailNow() - t.Run("seq", func(t *T) { - realTest.Error("test must be skipped") - }) - t.Run("par", func(t *T) { - t.Parallel() - realTest.Error("test must be skipped.") - }) - }) - if !ranPar { - realTest.Error("parallel test was not run") - } - if !ranSeq { - realTest.Error("sequential test was not run") - } - }, - }, { - desc: "failure in parallel test propagates upwards", - ok: false, - maxPar: 1, - output: ` ---- FAIL: failure in parallel test propagates upwards (N.NNs) - --- FAIL: failure in parallel test propagates upwards/#00 (N.NNs) - --- FAIL: failure in parallel test propagates upwards/#00/par (N.NNs) - `, - f: func(t *T) { - t.Run("", func(t *T) { - t.Parallel() - t.Run("par", func(t *T) { - t.Parallel() - t.Fail() - }) - }) - }, - }, { - desc: "skipping without message, chatty", - ok: true, - chatty: true, - output: ` -=== RUN skipping without message, chatty ---- SKIP: skipping without message, chatty (N.NNs)`, - f: func(t *T) { t.SkipNow() }, - }, { - desc: "chatty with recursion", - ok: true, - chatty: true, - output: ` -=== RUN chatty with recursion -=== RUN chatty with recursion/#00 -=== RUN chatty with recursion/#00/#00 ---- PASS: chatty with recursion (N.NNs) - --- PASS: chatty with recursion/#00 (N.NNs) - --- PASS: chatty with recursion/#00/#00 (N.NNs)`, - f: func(t *T) { - t.Run("", func(t *T) { - t.Run("", func(t *T) {}) - }) - }, - }, { - desc: "chatty with recursion and json", - ok: false, - chatty: true, - json: true, - output: ` -^V=== RUN chatty with recursion and json -^V=== RUN chatty with recursion and json/#00 -^V=== RUN chatty with recursion and json/#00/#00 -^V--- PASS: chatty with recursion and json/#00/#00 (N.NNs) -^V=== NAME chatty with recursion and json/#00 -^V=== RUN chatty with recursion and json/#00/#01 - sub_test.go:NNN: skip -^V--- SKIP: chatty with recursion and json/#00/#01 (N.NNs) -^V=== NAME chatty with recursion and json/#00 -^V=== RUN chatty with recursion and json/#00/#02 - sub_test.go:NNN: fail -^V--- FAIL: chatty with recursion and json/#00/#02 (N.NNs) -^V=== NAME chatty with recursion and json/#00 -^V--- FAIL: chatty with recursion and json/#00 (N.NNs) -^V=== NAME chatty with recursion and json -^V--- FAIL: chatty with recursion and json (N.NNs) -^V=== NAME `, - f: func(t *T) { - t.Run("", func(t *T) { - t.Run("", func(t *T) {}) - t.Run("", func(t *T) { t.Skip("skip") }) - t.Run("", func(t *T) { t.Fatal("fail") }) - }) - }, - }, { - desc: "skipping without message, not chatty", - ok: true, - f: func(t *T) { t.SkipNow() }, - }, { - desc: "skipping after error", - output: ` ---- FAIL: skipping after error (N.NNs) - sub_test.go:NNN: an error - sub_test.go:NNN: skipped`, - f: func(t *T) { - t.Error("an error") - t.Skip("skipped") - }, - }, { - desc: "use Run to locally synchronize parallelism", - ok: true, - maxPar: 1, - f: func(t *T) { - var count uint32 - t.Run("waitGroup", func(t *T) { - for i := 0; i < 4; i++ { - t.Run("par", func(t *T) { - t.Parallel() - atomic.AddUint32(&count, 1) - }) - } - }) - if count != 4 { - t.Errorf("count was %d; want 4", count) - } - }, - }, { - desc: "alternate sequential and parallel", - // Sequential tests should partake in the counting of running threads. - // Otherwise, if one runs parallel subtests in sequential tests that are - // itself subtests of parallel tests, the counts can get askew. - ok: true, - maxPar: 1, - f: func(t *T) { - t.Run("a", func(t *T) { - t.Parallel() - t.Run("b", func(t *T) { - // Sequential: ensure running count is decremented. - t.Run("c", func(t *T) { - t.Parallel() - }) - }) - }) - }, - }, { - desc: "alternate sequential and parallel 2", - // Sequential tests should partake in the counting of running threads. - // Otherwise, if one runs parallel subtests in sequential tests that are - // itself subtests of parallel tests, the counts can get askew. - ok: true, - maxPar: 2, - f: func(t *T) { - for i := 0; i < 2; i++ { - t.Run("a", func(t *T) { - t.Parallel() - time.Sleep(time.Nanosecond) - for i := 0; i < 2; i++ { - t.Run("b", func(t *T) { - time.Sleep(time.Nanosecond) - for i := 0; i < 2; i++ { - t.Run("c", func(t *T) { - t.Parallel() - time.Sleep(time.Nanosecond) - }) - } - }) - } - }) - } - }, - }, { - desc: "stress test", - ok: true, - maxPar: 4, - f: func(t *T) { - t.Parallel() - for i := 0; i < 12; i++ { - t.Run("a", func(t *T) { - t.Parallel() - time.Sleep(time.Nanosecond) - for i := 0; i < 12; i++ { - t.Run("b", func(t *T) { - time.Sleep(time.Nanosecond) - for i := 0; i < 12; i++ { - t.Run("c", func(t *T) { - t.Parallel() - time.Sleep(time.Nanosecond) - t.Run("d1", func(t *T) {}) - t.Run("d2", func(t *T) {}) - t.Run("d3", func(t *T) {}) - t.Run("d4", func(t *T) {}) - }) - } - }) - } - }) - } - }, - }, { - desc: "skip output", - ok: true, - maxPar: 4, - f: func(t *T) { - t.Skip() - }, - }, { - desc: "subtest calls error on parent", - ok: false, - output: ` ---- FAIL: subtest calls error on parent (N.NNs) - sub_test.go:NNN: first this - sub_test.go:NNN: and now this! - sub_test.go:NNN: oh, and this too`, - maxPar: 1, - f: func(t *T) { - t.Errorf("first this") - outer := t - t.Run("", func(t *T) { - outer.Errorf("and now this!") - }) - t.Errorf("oh, and this too") - }, - }, { - desc: "subtest calls fatal on parent", - ok: false, - output: ` ---- FAIL: subtest calls fatal on parent (N.NNs) - sub_test.go:NNN: first this - sub_test.go:NNN: and now this! - --- FAIL: subtest calls fatal on parent/#00 (N.NNs) - testing.go:NNN: test executed panic(nil) or runtime.Goexit: subtest may have called FailNow on a parent test`, - maxPar: 1, - f: func(t *T) { - outer := t - t.Errorf("first this") - t.Run("", func(t *T) { - outer.Fatalf("and now this!") - }) - t.Errorf("Should not reach here.") - }, - }, { - desc: "subtest calls error on ancestor", - ok: false, - output: ` ---- FAIL: subtest calls error on ancestor (N.NNs) - sub_test.go:NNN: Report to ancestor - --- FAIL: subtest calls error on ancestor/#00 (N.NNs) - sub_test.go:NNN: Still do this - sub_test.go:NNN: Also do this`, - maxPar: 1, - f: func(t *T) { - outer := t - t.Run("", func(t *T) { - t.Run("", func(t *T) { - outer.Errorf("Report to ancestor") - }) - t.Errorf("Still do this") - }) - t.Errorf("Also do this") - }, - }, { - desc: "subtest calls fatal on ancestor", - ok: false, - output: ` ---- FAIL: subtest calls fatal on ancestor (N.NNs) - sub_test.go:NNN: Nope`, - maxPar: 1, - f: func(t *T) { - outer := t - t.Run("", func(t *T) { - for i := 0; i < 4; i++ { - t.Run("", func(t *T) { - outer.Fatalf("Nope") - }) - t.Errorf("Don't do this") - } - t.Errorf("And neither do this") - }) - t.Errorf("Nor this") - }, - }, { - desc: "panic on goroutine fail after test exit", - ok: false, - maxPar: 4, - f: func(t *T) { - ch := make(chan bool) - t.Run("", func(t *T) { - go func() { - <-ch - defer func() { - if r := recover(); r == nil { - realTest.Errorf("expected panic") - } - ch <- true - }() - t.Errorf("failed after success") - }() - }) - ch <- true - <-ch - }, - }, { - desc: "log in finished sub test logs to parent", - ok: false, - output: ` - --- FAIL: log in finished sub test logs to parent (N.NNs) - sub_test.go:NNN: message2 - sub_test.go:NNN: message1 - sub_test.go:NNN: error`, - maxPar: 1, - f: func(t *T) { - ch := make(chan bool) - t.Run("sub", func(t2 *T) { - go func() { - <-ch - t2.Log("message1") - ch <- true - }() - }) - t.Log("message2") - ch <- true - <-ch - t.Errorf("error") - }, - }, { - // A chatty test should always log with fmt.Print, even if the - // parent test has completed. - desc: "log in finished sub test with chatty", - ok: false, - chatty: true, - output: ` - --- FAIL: log in finished sub test with chatty (N.NNs)`, - maxPar: 1, - f: func(t *T) { - ch := make(chan bool) - t.Run("sub", func(t2 *T) { - go func() { - <-ch - t2.Log("message1") - ch <- true - }() - }) - t.Log("message2") - ch <- true - <-ch - t.Errorf("error") - }, - }, { - // If a subtest panics we should run cleanups. - desc: "cleanup when subtest panics", - ok: false, - chatty: false, - output: ` ---- FAIL: cleanup when subtest panics (N.NNs) - --- FAIL: cleanup when subtest panics/sub (N.NNs) - sub_test.go:NNN: running cleanup`, - f: func(t *T) { - t.Cleanup(func() { t.Log("running cleanup") }) - t.Run("sub", func(t2 *T) { - t2.FailNow() - }) - }, - }, { - desc: "buffered output gets flushed at test end", - ok: false, - output: ` ---- FAIL: buffered output gets flushed at test end (N.NNs) - --- FAIL: buffered output gets flushed at test end/#00 (N.NNs) - a - b`, - f: func(t *T) { - t.Run("", func(t *T) { - o := t.Output() - o.Write([]byte("a\n")) - o.Write([]byte("b")) - t.Fail() - }) - }, - }, { - desc: "output with chatty", - ok: true, - chatty: true, - output: ` -=== RUN output with chatty -=== RUN output with chatty/#00 - a - b ---- PASS: output with chatty (N.NNs) - --- PASS: output with chatty/#00 (N.NNs)`, - f: func(t *T) { - t.Run("", func(t *T) { - o := t.Output() - o.Write([]byte("a\n")) - o.Write([]byte("b")) - }) - }, - }, { - desc: "output with chatty and json", - ok: true, - chatty: true, - json: true, - output: ` -^V=== RUN output with chatty and json -^V=== RUN output with chatty and json/#00 - a - b -^V--- PASS: output with chatty and json/#00 (N.NNs) -^V=== NAME output with chatty and json -^V--- PASS: output with chatty and json (N.NNs) -^V=== NAME -`, - f: func(t *T) { - t.Run("", func(t *T) { - o := t.Output() - o.Write([]byte("a\n")) - o.Write([]byte("b")) - }) - }, - }, { - desc: "output in finished sub test outputs to parent", - ok: false, - output: ` - --- FAIL: output in finished sub test outputs to parent (N.NNs) - message2 - message1 - sub_test.go:NNN: error`, - f: func(t *T) { - ch := make(chan bool) - t.Run("sub", func(t2 *T) { - go func() { - <-ch - t2.Output().Write([]byte("message1\n")) - ch <- true - }() - }) - t.Output().Write([]byte("message2\n")) - ch <- true - <-ch - t.Errorf("error") - }, - }, { - desc: "newline between buffered log and log", - ok: false, - output: ` ---- FAIL: newline between buffered log and log (N.NNs) - --- FAIL: newline between buffered log and log/#00 (N.NNs) - buffered message - sub_test.go:NNN: log`, - f: func(t *T) { - t.Run("", func(t *T) { - o := t.Output() - o.Write([]byte("buffered message")) - t.Log("log") - t.Fail() - }) - }, - }} - for _, tc := range testCases { - t.Run(tc.desc, func(t *T) { - tstate := newTestState(tc.maxPar, allMatcher()) - buf := &strings.Builder{} - root := &T{ - common: common{ - signal: make(chan bool), - barrier: make(chan bool), - name: "", - w: buf, - }, - tstate: tstate, - } - if tc.chatty { - root.chatty = newChattyPrinter(root.w) - root.chatty.json = tc.json - } - ok := root.Run(tc.desc, tc.f) - tstate.release() - - if ok != tc.ok { - t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok) - } - if ok != !root.Failed() { - t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) - } - if tstate.running != 0 || tstate.numWaiting != 0 { - t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, tstate.running, tstate.numWaiting) - } - got := strings.TrimSpace(buf.String()) - want := strings.TrimSpace(tc.output) - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) - } - }) - } -} - -func TestBRun(t *T) { - work := func(b *B) { - for i := 0; i < b.N; i++ { - time.Sleep(time.Nanosecond) - } - } - testCases := []struct { - desc string - failed bool - chatty bool - output string - f func(*B) - }{{ - desc: "simulate sequential run of subbenchmarks.", - f: func(b *B) { - b.Run("", func(b *B) { work(b) }) - time1 := b.result.NsPerOp() - b.Run("", func(b *B) { work(b) }) - time2 := b.result.NsPerOp() - if time1 >= time2 { - t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2) - } - }, - }, { - desc: "bytes set by all benchmarks", - f: func(b *B) { - b.Run("", func(b *B) { b.SetBytes(10); work(b) }) - b.Run("", func(b *B) { b.SetBytes(10); work(b) }) - if b.result.Bytes != 20 { - t.Errorf("bytes: got: %d; want 20", b.result.Bytes) - } - }, - }, { - desc: "bytes set by some benchmarks", - // In this case the bytes result is meaningless, so it must be 0. - f: func(b *B) { - b.Run("", func(b *B) { b.SetBytes(10); work(b) }) - b.Run("", func(b *B) { work(b) }) - b.Run("", func(b *B) { b.SetBytes(10); work(b) }) - if b.result.Bytes != 0 { - t.Errorf("bytes: got: %d; want 0", b.result.Bytes) - } - }, - }, { - desc: "failure carried over to root", - failed: true, - output: "--- FAIL: root", - f: func(b *B) { b.Fail() }, - }, { - desc: "skipping without message, chatty", - chatty: true, - output: "--- SKIP: root", - f: func(b *B) { b.SkipNow() }, - }, { - desc: "chatty with recursion", - chatty: true, - f: func(b *B) { - b.Run("", func(b *B) { - b.Run("", func(b *B) {}) - }) - }, - }, { - desc: "skipping without message, not chatty", - f: func(b *B) { b.SkipNow() }, - }, { - desc: "skipping after error", - failed: true, - output: ` ---- FAIL: root - sub_test.go:NNN: an error - sub_test.go:NNN: skipped`, - f: func(b *B) { - b.Error("an error") - b.Skip("skipped") - }, - }, { - desc: "memory allocation", - f: func(b *B) { - const bufSize = 256 - alloc := func(b *B) { - var buf [bufSize]byte - for i := 0; i < b.N; i++ { - _ = append([]byte(nil), buf[:]...) - } - } - b.Run("", func(b *B) { - alloc(b) - b.ReportAllocs() - }) - b.Run("", func(b *B) { - alloc(b) - b.ReportAllocs() - }) - // runtime.MemStats sometimes reports more allocations than the - // benchmark is responsible for. Luckily the point of this test is - // to ensure that the results are not underreported, so we can - // simply verify the lower bound. - if got := b.result.MemAllocs; got < 2 { - t.Errorf("MemAllocs was %v; want 2", got) - } - if got := b.result.MemBytes; got < 2*bufSize { - t.Errorf("MemBytes was %v; want %v", got, 2*bufSize) - } - }, - }, { - desc: "cleanup is called", - f: func(b *B) { - var calls, cleanups, innerCalls, innerCleanups int - b.Run("", func(b *B) { - calls++ - b.Cleanup(func() { - cleanups++ - }) - b.Run("", func(b *B) { - b.Cleanup(func() { - innerCleanups++ - }) - innerCalls++ - }) - work(b) - }) - if calls == 0 || calls != cleanups { - t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls) - } - if innerCalls == 0 || innerCalls != innerCleanups { - t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls) - } - }, - }, { - desc: "cleanup is called on failure", - failed: true, - f: func(b *B) { - var calls, cleanups int - b.Run("", func(b *B) { - calls++ - b.Cleanup(func() { - cleanups++ - }) - b.Fatalf("failure") - }) - if calls == 0 || calls != cleanups { - t.Errorf("mismatched cleanups; got %d want %d", cleanups, calls) - } - }, - }} - hideStdoutForTesting = true - defer func() { - hideStdoutForTesting = false - }() - for _, tc := range testCases { - t.Run(tc.desc, func(t *T) { - var ok bool - buf := &strings.Builder{} - // This is almost like the Benchmark function, except that we override - // the benchtime and catch the failure result of the subbenchmark. - root := &B{ - common: common{ - signal: make(chan bool), - name: "root", - w: buf, - }, - benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure. - benchTime: durationOrCountFlag{d: 1 * time.Microsecond}, - } - if tc.chatty { - root.chatty = newChattyPrinter(root.w) - } - root.runN(1) - if ok != !tc.failed { - t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed) - } - if !ok != root.Failed() { - t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed()) - } - // All tests are run as subtests - if root.result.N != 1 { - t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N) - } - got := strings.TrimSpace(buf.String()) - want := strings.TrimSpace(tc.output) - re := makeRegexp(want) - if ok, err := regexp.MatchString(re, got); !ok || err != nil { - t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want) - } - }) - } -} - -func makeRegexp(s string) string { - s = regexp.QuoteMeta(s) - s = strings.ReplaceAll(s, "^V", "\x16") - s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`) - s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`) - return s -} - -func TestBenchmarkOutput(t *T) { - // Ensure Benchmark initialized common.w by invoking it with an error and - // normal case. - Benchmark(func(b *B) { b.Error("do not print this output") }) - Benchmark(func(b *B) {}) -} - -func TestBenchmarkStartsFrom1(t *T) { - first := true - Benchmark(func(b *B) { - if first && b.N != 1 { - panic(fmt.Sprintf("Benchmark() first N=%v; want 1", b.N)) - } - first = false - }) -} - -func TestBenchmarkReadMemStatsBeforeFirstRun(t *T) { - first := true - Benchmark(func(b *B) { - if first && (b.startAllocs == 0 || b.startBytes == 0) { - panic("ReadMemStats not called before first run") - } - first = false - }) -} - -type funcWriter struct { - write func([]byte) (int, error) -} - -func (fw *funcWriter) Write(b []byte) (int, error) { - return fw.write(b) -} - -func TestRacyOutput(t *T) { - var runs int32 // The number of running Writes - var races int32 // Incremented for each race detected - raceDetector := func(b []byte) (int, error) { - // Check if some other goroutine is concurrently calling Write. - if atomic.LoadInt32(&runs) > 0 { - atomic.AddInt32(&races, 1) // Race detected! - } - atomic.AddInt32(&runs, 1) - defer atomic.AddInt32(&runs, -1) - runtime.Gosched() // Increase probability of a race - return len(b), nil - } - - root := &T{ - common: common{w: &funcWriter{raceDetector}}, - tstate: newTestState(1, allMatcher()), - } - root.chatty = newChattyPrinter(root.w) - root.Run("", func(t *T) { - var wg sync.WaitGroup - for i := 0; i < 100; i++ { - wg.Add(1) - go func(i int) { - defer wg.Done() - t.Run(fmt.Sprint(i), func(t *T) { - t.Logf("testing run %d", i) - }) - }(i) - } - wg.Wait() - }) - - if races > 0 { - t.Errorf("detected %d racy Writes", races) - } -} - -// The late log message did not include the test name. Issue 29388. -func TestLogAfterComplete(t *T) { - tstate := newTestState(1, allMatcher()) - var buf bytes.Buffer - t1 := &T{ - common: common{ - // Use a buffered channel so that tRunner can write - // to it although nothing is reading from it. - signal: make(chan bool, 1), - w: &buf, - }, - tstate: tstate, - } - - c1 := make(chan bool) - c2 := make(chan string) - tRunner(t1, func(t *T) { - t.Run("TestLateLog", func(t *T) { - go func() { - defer close(c2) - defer func() { - p := recover() - if p == nil { - c2 <- "subtest did not panic" - return - } - s, ok := p.(string) - if !ok { - c2 <- fmt.Sprintf("subtest panic with unexpected value %v of type %T", p, p) - return - } - const want = "Log in goroutine after TestLateLog has completed: log after test" - if !strings.Contains(s, want) { - c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want) - } - }() - - <-c1 - t.Log("log after test") - }() - }) - }) - close(c1) - - if s := <-c2; s != "" { - t.Error(s) - } -} - -func TestBenchmark(t *T) { - if Short() { - t.Skip("skipping in short mode") - } - res := Benchmark(func(b *B) { - for i := 0; i < 5; i++ { - b.Run("", func(b *B) { - for i := 0; i < b.N; i++ { - time.Sleep(time.Millisecond) - } - }) - } - }) - if res.NsPerOp() < 4000000 { - t.Errorf("want >5ms; got %v", time.Duration(res.NsPerOp())) - } -} - -func TestCleanup(t *T) { - var cleanups []int - t.Run("test", func(t *T) { - t.Cleanup(func() { cleanups = append(cleanups, 1) }) - t.Cleanup(func() { cleanups = append(cleanups, 2) }) - }) - if got, want := cleanups, []int{2, 1}; !slices.Equal(got, want) { - t.Errorf("unexpected cleanup record; got %v want %v", got, want) - } -} - -func TestConcurrentCleanup(t *T) { - cleanups := 0 - t.Run("test", func(t *T) { - var wg sync.WaitGroup - wg.Add(2) - for i := 0; i < 2; i++ { - i := i - go func() { - t.Cleanup(func() { - // Although the calls to Cleanup are concurrent, the functions passed - // to Cleanup should be called sequentially, in some nondeterministic - // order based on when the Cleanup calls happened to be scheduled. - // So these assignments to the cleanups variable should not race. - cleanups |= 1 << i - }) - wg.Done() - }() - } - wg.Wait() - }) - if cleanups != 1|2 { - t.Errorf("unexpected cleanup; got %d want 3", cleanups) - } -} - -func TestCleanupCalledEvenAfterGoexit(t *T) { - cleanups := 0 - t.Run("test", func(t *T) { - t.Cleanup(func() { - cleanups++ - }) - t.Cleanup(func() { - runtime.Goexit() - }) - }) - if cleanups != 1 { - t.Errorf("unexpected cleanup count; got %d want 1", cleanups) - } -} - -func TestRunCleanup(t *T) { - outerCleanup := 0 - innerCleanup := 0 - t.Run("test", func(t *T) { - t.Cleanup(func() { outerCleanup++ }) - t.Run("x", func(t *T) { - t.Cleanup(func() { innerCleanup++ }) - }) - }) - if innerCleanup != 1 { - t.Errorf("unexpected inner cleanup count; got %d want 1", innerCleanup) - } - if outerCleanup != 1 { - t.Errorf("unexpected outer cleanup count; got %d want 0", outerCleanup) - } -} - -func TestCleanupParallelSubtests(t *T) { - ranCleanup := 0 - t.Run("test", func(t *T) { - t.Cleanup(func() { ranCleanup++ }) - t.Run("x", func(t *T) { - t.Parallel() - if ranCleanup > 0 { - t.Error("outer cleanup ran before parallel subtest") - } - }) - }) - if ranCleanup != 1 { - t.Errorf("unexpected cleanup count; got %d want 1", ranCleanup) - } -} - -func TestNestedCleanup(t *T) { - ranCleanup := 0 - t.Run("test", func(t *T) { - t.Cleanup(func() { - if ranCleanup != 2 { - t.Errorf("unexpected cleanup count in first cleanup: got %d want 2", ranCleanup) - } - ranCleanup++ - }) - t.Cleanup(func() { - if ranCleanup != 0 { - t.Errorf("unexpected cleanup count in second cleanup: got %d want 0", ranCleanup) - } - ranCleanup++ - t.Cleanup(func() { - if ranCleanup != 1 { - t.Errorf("unexpected cleanup count in nested cleanup: got %d want 1", ranCleanup) - } - ranCleanup++ - }) - }) - }) - if ranCleanup != 3 { - t.Errorf("unexpected cleanup count: got %d want 3", ranCleanup) - } -} - -// TestOutput checks that log messages are written, -// formatted and buffered as expected by Output. It -// checks both the chatty and non-chatty cases. -func TestOutput(t *T) { - tstate := newTestState(1, allMatcher()) - root := &T{ - tstate: tstate, - } - root.setOutputWriter() - o := root.Output() - - // Chatty case - tstateChatty := newTestState(1, allMatcher()) - bufChatty := &strings.Builder{} - rootChatty := &T{ - common: common{ - w: bufChatty, - }, - tstate: tstateChatty, - } - rootChatty.setOutputWriter() - rootChatty.chatty = newChattyPrinter(rootChatty.w) - oChatty := rootChatty.Output() - - testCases := []struct { - in string - out string - buf string - }{{ - in: "a", - out: "", - buf: "a", - }, { - in: "b", - out: "", - buf: "ab", - }, { - in: "\n", - out: " ab\n", - buf: "", - }, { - in: "\nc", - out: " ab\n \n", - buf: "c", - }, { - in: "d", - out: " ab\n \n", - buf: "cd", - }} - for _, tc := range testCases { - o.Write([]byte(tc.in)) - if string(root.output) != tc.out { - t.Errorf("output:\ngot:\n%s\nwant:\n%s", root.output, tc.out) - } - if string(root.o.partial) != tc.buf { - t.Errorf("buffer:\ngot:\n%s\nwant:\n%s", root.o.partial, tc.buf) - } - - // Chatty case - oChatty.Write([]byte(tc.in)) - if got := bufChatty.String(); got != tc.out { - t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, tc.out) - } - } -} - -// TestOutputAfterComplete ensures that Output panics -// if called after a test function returns. -func TestOutputAfterComplete(t *T) { - tstate := newTestState(1, allMatcher()) - var buf bytes.Buffer - t1 := &T{ - common: common{ - // Use a buffered channel so that tRunner can write - // to it although nothing is reading from it. - signal: make(chan bool, 1), - w: &buf, - }, - tstate: tstate, - } - - c1 := make(chan bool) - c2 := make(chan string) - tRunner(t1, func(t *T) { - t.Run("TestLateOutput", func(t *T) { - go func() { - defer close(c2) - defer func() { - p := recover() - if p == nil { - c2 <- "subtest did not panic" - return - } - s, ok := p.(string) - if !ok { - c2 <- fmt.Sprintf("subtest panic with unexpected value %v of type %T", p, p) - return - } - const want = "Output called after TestLateOutput has completed" - if !strings.Contains(s, want) { - c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want) - } - }() - - <-c1 - t.Output() - }() - }) - }) - close(c1) - - if s := <-c2; s != "" { - t.Error(s) - } -} - -// TestOutputWriteAfterComplete ensures that Write panics -// if called on t.Output() of a finished test t. -func TestOutputWriteAfterComplete(t *T) { - tstate := newTestState(1, allMatcher()) - var buf bytes.Buffer - t1 := &T{ - common: common{ - // Use a buffered channel so that tRunner can write - // to it although nothing is reading from it. - signal: make(chan bool, 1), - w: &buf, - }, - tstate: tstate, - } - - c1 := make(chan bool) - c2 := make(chan string) - tRunner(t1, func(t *T) { - t.Run("TestLateWrite", func(t *T) { - o := t.Output() - go func() { - defer close(c2) - defer func() { - p := recover() - if p == nil { - c2 <- "subtest did not panic" - return - } - s, ok := p.(string) - if !ok { - c2 <- fmt.Sprintf("subtest panic with unexpected value %v of type %T", p, p) - return - } - const want = "Write called after TestLateWrite has completed" - if !strings.Contains(s, want) { - c2 <- fmt.Sprintf("subtest panic %q does not contain %q", s, want) - } - }() - - <-c1 - o.Write([]byte("write after test")) - }() - }) - }) - close(c1) - - if s := <-c2; s != "" { - t.Error(s) - } -} - -// Verify that logging to an inactive top-level testing.T does not panic. -// These tests can run in either order. - -func TestOutputEscape1(t *T) { testOutputEscape(t) } -func TestOutputEscape2(t *T) { testOutputEscape(t) } - -var global *T - -func testOutputEscape(t *T) { - if global == nil { - // Store t in a global, to set up for the second execution. - global = t - } else { - // global is inactive here. - global.Log("hello") - } -} diff --git a/testing/testing/synctest/example_test.go b/testing/testing/synctest/example_test.go deleted file mode 100644 index 843377ea..00000000 --- a/testing/testing/synctest/example_test.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2024 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 synctest_test - -import ( - "bufio" - "bytes" - "context" - "io" - "net" - "net/http" - "strings" - "testing" - "testing/synctest" - "time" -) - -// Keep the following tests in sync with the package documentation. - -func TestTime(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - start := time.Now() // always midnight UTC 2000-01-01 - go func() { - time.Sleep(1 * time.Nanosecond) - t.Log(time.Since(start)) // always logs "1ns" - }() - time.Sleep(2 * time.Nanosecond) // the AfterFunc will run before this Sleep returns - t.Log(time.Since(start)) // always logs "2ns" - }) -} - -func TestWait(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - done := false - go func() { - done = true - }() - // Wait will block until the goroutine above has finished. - synctest.Wait() - t.Log(done) // always logs "true" - }) -} - -func TestContextAfterFunc(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - // Create a context.Context which can be canceled. - ctx, cancel := context.WithCancel(t.Context()) - - // context.AfterFunc registers a function to be called - // when a context is canceled. - afterFuncCalled := false - context.AfterFunc(ctx, func() { - afterFuncCalled = true - }) - - // The context has not been canceled, so the AfterFunc is not called. - synctest.Wait() - if afterFuncCalled { - t.Fatalf("before context is canceled: AfterFunc called") - } - - // Cancel the context and wait for the AfterFunc to finish executing. - // Verify that the AfterFunc ran. - cancel() - synctest.Wait() - if !afterFuncCalled { - t.Fatalf("before context is canceled: AfterFunc not called") - } - }) -} - -func TestContextWithTimeout(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - // Create a context.Context which is canceled after a timeout. - const timeout = 5 * time.Second - ctx, cancel := context.WithTimeout(t.Context(), timeout) - defer cancel() - - // Wait just less than the timeout. - time.Sleep(timeout - time.Nanosecond) - synctest.Wait() - if err := ctx.Err(); err != nil { - t.Fatalf("before timeout: ctx.Err() = %v, want nil\n", err) - } - - // Wait the rest of the way until the timeout. - time.Sleep(time.Nanosecond) - synctest.Wait() - if err := ctx.Err(); err != context.DeadlineExceeded { - t.Fatalf("after timeout: ctx.Err() = %v, want DeadlineExceeded\n", err) - } - }) -} - -func TestHTTPTransport100Continue(t *testing.T) { - synctest.Test(t, func(*testing.T) { - // Create an in-process fake network connection. - // We cannot use a loopback network connection for this test, - // because goroutines blocked on network I/O prevent a synctest - // bubble from becoming idle. - srvConn, cliConn := net.Pipe() - defer cliConn.Close() - defer srvConn.Close() - - tr := &http.Transport{ - // Use the fake network connection created above. - DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - return cliConn, nil - }, - // Enable "Expect: 100-continue" handling. - ExpectContinueTimeout: 5 * time.Second, - } - - // Send a request with the "Expect: 100-continue" header set. - // Send it in a new goroutine, since it won't complete until the end of the test. - body := "request body" - go func() { - req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) - req.Header.Set("Expect", "100-continue") - resp, err := tr.RoundTrip(req) - if err != nil { - t.Errorf("RoundTrip: unexpected error %v\n", err) - } else { - resp.Body.Close() - } - }() - - // Read the request headers sent by the client. - req, err := http.ReadRequest(bufio.NewReader(srvConn)) - if err != nil { - t.Fatalf("ReadRequest: %v\n", err) - } - - // Start a new goroutine copying the body sent by the client into a buffer. - // Wait for all goroutines in the bubble to block and verify that we haven't - // read anything from the client yet. - var gotBody bytes.Buffer - go io.Copy(&gotBody, req.Body) - synctest.Wait() - if got, want := gotBody.String(), ""; got != want { - t.Fatalf("before sending 100 Continue, read body: %q, want %q\n", got, want) - } - - // Write a "100 Continue" response to the client and verify that - // it sends the request body. - srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n")) - synctest.Wait() - if got, want := gotBody.String(), body; got != want { - t.Fatalf("after sending 100 Continue, read body: %q, want %q\n", got, want) - } - - // Finish up by sending the "200 OK" response to conclude the request. - srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) - - // We started several goroutines during the test. - // The synctest.Test call will wait for all of them to exit before returning. - }) -} diff --git a/testing/testing/synctest/helper_test.go b/testing/testing/synctest/helper_test.go deleted file mode 100644 index 7547d3ea..00000000 --- a/testing/testing/synctest/helper_test.go +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -package synctest_test - -import "testing" - -// helperLog is a t.Helper which logs. -// Since it is a helper, the log prefix should contain -// the caller's file, not helper_test.go. -func helperLog(t *testing.T, s string) { - t.Helper() - t.Log(s) -} diff --git a/testing/testing/synctest/run.go b/testing/testing/synctest/run.go deleted file mode 100644 index 9fef9f69..00000000 --- a/testing/testing/synctest/run.go +++ /dev/null @@ -1,16 +0,0 @@ -// 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 goexperiment.synctest - -package synctest - -import "github.com/CodSpeedHQ/codspeed-go/testing/internal/synctest" - -// Run is deprecated. -// -// Deprecated: Use Test instead. Run will be removed in Go 1.26. -func Run(f func()) { - synctest.Run(f) -} diff --git a/testing/testing/synctest/synctest.go b/testing/testing/synctest/synctest.go deleted file mode 100644 index 83e89124..00000000 --- a/testing/testing/synctest/synctest.go +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright 2024 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 synctest provides support for testing concurrent code. -// -// The [Test] function runs a function in an isolated "bubble". -// Any goroutines started within the bubble are also part of the bubble. -// -// # Time -// -// Within a bubble, the [time] package uses a fake clock. -// Each bubble has its own clock. -// The initial time is midnight UTC 2000-01-01. -// -// Time in a bubble only advances when every goroutine in the -// bubble is durably blocked. -// See below for the exact definition of "durably blocked". -// -// For example, this test runs immediately rather than taking -// two seconds: -// -// func TestTime(t *testing.T) { -// synctest.Test(t, func(t *testing.T) { -// start := time.Now() // always midnight UTC 2000-01-01 -// go func() { -// time.Sleep(1 * time.Second) -// t.Log(time.Since(start)) // always logs "1s" -// }() -// time.Sleep(2 * time.Second) // the goroutine above will run before this Sleep returns -// t.Log(time.Since(start)) // always logs "2s" -// }) -// } -// -// Time stops advancing when the root goroutine of the bubble exits. -// -// # Blocking -// -// A goroutine in a bubble is "durably blocked" when it is blocked -// and can only be unblocked by another goroutine in the same bubble. -// A goroutine which can be unblocked by an event from outside its -// bubble is not durably blocked. -// -// The [Wait] function blocks until all other goroutines in the -// bubble are durably blocked. -// -// For example: -// -// func TestWait(t *testing.T) { -// synctest.Test(t, func(t *testing.T) { -// done := false -// go func() { -// done = true -// }() -// // Wait will block until the goroutine above has finished. -// synctest.Wait() -// t.Log(done) // always logs "true" -// }) -// } -// -// When every goroutine in a bubble is durably blocked: -// -// - [Wait] returns, if it has been called. -// - Otherwise, time advances to the next time that will -// unblock at least one goroutine, if there is such a time -// and the root goroutine of the bubble has not exited. -// - Otherwise, there is a deadlock and [Test] panics. -// -// The following operations durably block a goroutine: -// -// - a blocking send or receive on a channel created within the bubble -// - a blocking select statement where every case is a channel created -// within the bubble -// - [sync.Cond.Wait] -// - [sync.WaitGroup.Wait], when [sync.WaitGroup.Add] was called within the bubble -// - [time.Sleep] -// -// Operations not in the above list are not durably blocking. -// In particular, the following operations may block a goroutine, -// but are not durably blocking because the goroutine can be unblocked -// by an event occurring outside its bubble: -// -// - locking a [sync.Mutex] or [sync.RWMutex] -// - blocking on I/O, such as reading from a network socket -// - system calls -// -// # Isolation -// -// A channel, [time.Timer], or [time.Ticker] created within a bubble -// is associated with it. Operating on a bubbled channel, timer, or -// ticker from outside the bubble panics. -// -// A [sync.WaitGroup] becomes associated with a bubble on the first -// call to Add or Go. Once a WaitGroup is associated with a bubble, -// calling Add or Go from outside that bubble is a fatal error. -// (As a technical limitation, a WaitGroup defined as a package -// variable, such as "var wg sync.WaitGroup", cannot be associated -// with a bubble and operations on it may not be durably blocking. -// This limitation does not apply to a *WaitGroup stored in a -// package variable, such as "var wg = new(sync.WaitGroup)".) -// -// [sync.Cond.Wait] is durably blocking. Waking a goroutine in a bubble -// blocked on Cond.Wait from outside the bubble is a fatal error. -// -// Cleanup functions and finalizers registered with -// [runtime.AddCleanup] and [runtime.SetFinalizer] -// run outside of any bubble. -// -// # Example: Context.AfterFunc -// -// This example demonstrates testing the [context.AfterFunc] function. -// -// AfterFunc registers a function to execute in a new goroutine -// after a context is canceled. -// -// The test verifies that the function is not run before the context is canceled, -// and is run after the context is canceled. -// -// func TestContextAfterFunc(t *testing.T) { -// synctest.Test(t, func(t *testing.T) { -// // Create a context.Context which can be canceled. -// ctx, cancel := context.WithCancel(t.Context()) -// -// // context.AfterFunc registers a function to be called -// // when a context is canceled. -// afterFuncCalled := false -// context.AfterFunc(ctx, func() { -// afterFuncCalled = true -// }) -// -// // The context has not been canceled, so the AfterFunc is not called. -// synctest.Wait() -// if afterFuncCalled { -// t.Fatalf("before context is canceled: AfterFunc called") -// } -// -// // Cancel the context and wait for the AfterFunc to finish executing. -// // Verify that the AfterFunc ran. -// cancel() -// synctest.Wait() -// if !afterFuncCalled { -// t.Fatalf("before context is canceled: AfterFunc not called") -// } -// }) -// } -// -// # Example: Context.WithTimeout -// -// This example demonstrates testing the [context.WithTimeout] function. -// -// WithTimeout creates a context which is canceled after a timeout. -// -// The test verifies that the context is not canceled before the timeout expires, -// and is canceled after the timeout expires. -// -// func TestContextWithTimeout(t *testing.T) { -// synctest.Test(t, func(t *testing.T) { -// // Create a context.Context which is canceled after a timeout. -// const timeout = 5 * time.Second -// ctx, cancel := context.WithTimeout(t.Context(), timeout) -// defer cancel() -// -// // Wait just less than the timeout. -// time.Sleep(timeout - time.Nanosecond) -// synctest.Wait() -// if err := ctx.Err(); err != nil { -// t.Fatalf("before timeout: ctx.Err() = %v, want nil\n", err) -// } -// -// // Wait the rest of the way until the timeout. -// time.Sleep(time.Nanosecond) -// synctest.Wait() -// if err := ctx.Err(); err != context.DeadlineExceeded { -// t.Fatalf("after timeout: ctx.Err() = %v, want DeadlineExceeded\n", err) -// } -// }) -// } -// -// # Example: HTTP 100 Continue -// -// This example demonstrates testing [http.Transport]'s 100 Continue handling. -// -// An HTTP client sending a request can include an "Expect: 100-continue" header -// to tell the server that the client has additional data to send. -// The server may then respond with an 100 Continue information response -// to request the data, or some other status to tell the client the data is not needed. -// For example, a client uploading a large file might use this feature to confirm -// that the server is willing to accept the file before sending it. -// -// This test confirms that when sending an "Expect: 100-continue" header -// the HTTP client does not send a request's content before the server requests it, -// and that it does send the content after receiving a 100 Continue response. -// -// func TestHTTPTransport100Continue(t *testing.T) { -// synctest.Test(t, func(*testing.T) { -// // Create an in-process fake network connection. -// // We cannot use a loopback network connection for this test, -// // because goroutines blocked on network I/O prevent a synctest -// // bubble from becoming idle. -// srvConn, cliConn := net.Pipe() -// defer cliConn.Close() -// defer srvConn.Close() -// -// tr := &http.Transport{ -// // Use the fake network connection created above. -// DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { -// return cliConn, nil -// }, -// // Enable "Expect: 100-continue" handling. -// ExpectContinueTimeout: 5 * time.Second, -// } -// -// // Send a request with the "Expect: 100-continue" header set. -// // Send it in a new goroutine, since it won't complete until the end of the test. -// body := "request body" -// go func() { -// req, _ := http.NewRequest("PUT", "http://test.tld/", strings.NewReader(body)) -// req.Header.Set("Expect", "100-continue") -// resp, err := tr.RoundTrip(req) -// if err != nil { -// t.Errorf("RoundTrip: unexpected error %v\n", err) -// } else { -// resp.Body.Close() -// } -// }() -// -// // Read the request headers sent by the client. -// req, err := http.ReadRequest(bufio.NewReader(srvConn)) -// if err != nil { -// t.Fatalf("ReadRequest: %v\n", err) -// } -// -// // Start a new goroutine copying the body sent by the client into a buffer. -// // Wait for all goroutines in the bubble to block and verify that we haven't -// // read anything from the client yet. -// var gotBody bytes.Buffer -// go io.Copy(&gotBody, req.Body) -// synctest.Wait() -// if got, want := gotBody.String(), ""; got != want { -// t.Fatalf("before sending 100 Continue, read body: %q, want %q\n", got, want) -// } -// -// // Write a "100 Continue" response to the client and verify that -// // it sends the request body. -// srvConn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n")) -// synctest.Wait() -// if got, want := gotBody.String(), body; got != want { -// t.Fatalf("after sending 100 Continue, read body: %q, want %q\n", got, want) -// } -// -// // Finish up by sending the "200 OK" response to conclude the request. -// srvConn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) -// -// // We started several goroutines during the test. -// // The synctest.Test call will wait for all of them to exit before returning. -// }) -// } -package synctest - -import ( - "github.com/CodSpeedHQ/codspeed-go/testing/internal/synctest" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - _ "unsafe" // for linkname -) - -// Test executes f in a new bubble. -// -// Test waits for all goroutines in the bubble to exit before returning. -// If the goroutines in the bubble become deadlocked, the test fails. -// -// Test must not be called from within a bubble. -// -// The [*testing.T] provided to f has the following properties: -// -// - T.Cleanup functions run inside the bubble, -// immediately before Test returns. -// - T.Context returns a [context.Context] with a Done channel -// associated with the bubble. -// - T.Run, T.Parallel, and T.Deadline must not be called. -func Test(t *testing.T, f func(*testing.T)) { - var ok bool - synctest.Run(func() { - ok = testingSynctestTest_codspeed(t, f) - }) - if !ok { - // Fail the test outside the bubble, - // so test durations get set using real time. - t.FailNow() - } -} - -// NOTE(CODSPEED): This has to be renamed because the linked has a blocklist with the exact name: https://github.com/golang/go/blob/ad3ccd92e4c2ddfc1499a5e038eb0aa0012c0dda/src/cmd/link/internal/loader/loader.go#L2469 -// -//go:linkname testingSynctestTest_codspeed testing/synctest.testingSynctestTest_codspeed -func testingSynctestTest_codspeed(t *testing.T, f func(*testing.T)) bool - -// Wait blocks until every goroutine within the current bubble, -// other than the current goroutine, is durably blocked. -// -// Wait must not be called from outside a bubble. -// Wait must not be called concurrently by multiple goroutines -// in the same bubble. -func Wait() { - synctest.Wait() -} diff --git a/testing/testing/synctest/synctest_test.go b/testing/testing/synctest/synctest_test.go deleted file mode 100644 index 14a36941..00000000 --- a/testing/testing/synctest/synctest_test.go +++ /dev/null @@ -1,190 +0,0 @@ -// 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. - -package synctest_test - -import ( - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "regexp" - "testing" - "testing/synctest" - "time" -) - -// Tests for interactions between synctest bubbles and the testing package. -// Other bubble behaviors are tested in internal/synctest. - -func TestSuccess(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - }) -} - -func TestFatal(t *testing.T) { - runTest(t, nil, func() { - synctest.Test(t, func(t *testing.T) { - t.Fatal("fatal") - }) - }, `^--- FAIL: TestFatal.* - synctest_test.go:.* fatal -FAIL -$`) -} - -func TestError(t *testing.T) { - runTest(t, nil, func() { - synctest.Test(t, func(t *testing.T) { - t.Error("error") - }) - }, `^--- FAIL: TestError.* - synctest_test.go:.* error -FAIL -$`) -} - -func TestVerboseError(t *testing.T) { - runTest(t, []string{"-test.v"}, func() { - synctest.Test(t, func(t *testing.T) { - t.Error("error") - }) - }, `^=== RUN TestVerboseError - synctest_test.go:.* error ---- FAIL: TestVerboseError.* -FAIL -$`) -} - -func TestSkip(t *testing.T) { - runTest(t, nil, func() { - synctest.Test(t, func(t *testing.T) { - t.Skip("skip") - }) - }, `^PASS -$`) -} - -func TestVerboseSkip(t *testing.T) { - runTest(t, []string{"-test.v"}, func() { - synctest.Test(t, func(t *testing.T) { - t.Skip("skip") - }) - }, `^=== RUN TestVerboseSkip - synctest_test.go:.* skip ---- PASS: TestVerboseSkip.* -PASS -$`) -} - -func TestCleanup(t *testing.T) { - done := false - synctest.Test(t, func(t *testing.T) { - ch := make(chan struct{}) - t.Cleanup(func() { - // This cleanup function should execute inside the test's bubble. - // (If it doesn't the runtime will panic.) - close(ch) - }) - // synctest.Test will wait for this goroutine to exit before returning. - // The cleanup function signals the goroutine to exit before the wait starts. - go func() { - <-ch - done = true - }() - }) - if !done { - t.Fatalf("background goroutine did not return") - } -} - -func TestContext(t *testing.T) { - state := "not started" - synctest.Test(t, func(t *testing.T) { - go func() { - state = "waiting on context" - <-t.Context().Done() - state = "done" - }() - // Wait blocks until the goroutine above is blocked on t.Context().Done(). - synctest.Wait() - if got, want := state, "waiting on context"; got != want { - t.Fatalf("state = %q, want %q", got, want) - } - }) - // t.Context() is canceled before the test completes, - // and synctest.Test does not return until the goroutine has set its state to "done". - if got, want := state, "done"; got != want { - t.Fatalf("state = %q, want %q", got, want) - } -} - -func TestDeadline(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - defer wantPanic(t, "testing: t.Deadline called inside synctest bubble") - _, _ = t.Deadline() - }) -} - -func TestParallel(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - defer wantPanic(t, "testing: t.Parallel called inside synctest bubble") - t.Parallel() - }) -} - -func TestRun(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - defer wantPanic(t, "testing: t.Run called inside synctest bubble") - t.Run("subtest", func(t *testing.T) { - }) - }) -} - -func TestHelper(t *testing.T) { - runTest(t, []string{"-test.v"}, func() { - synctest.Test(t, func(t *testing.T) { - helperLog(t, "log in helper") - }) - }, `^=== RUN TestHelper - synctest_test.go:.* log in helper ---- PASS: TestHelper.* -PASS -$`) -} - -func wantPanic(t *testing.T, want string) { - if e := recover(); e != nil { - if got := fmt.Sprint(e); got != want { - t.Errorf("got panic message %q, want %q", got, want) - } - } else { - t.Errorf("got no panic, want one") - } -} - -func runTest(t *testing.T, args []string, f func(), pattern string) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - f() - return - } - t.Helper() - re := regexp.MustCompile(pattern) - testenv.MustHaveExec(t) - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+regexp.QuoteMeta(t.Name())+"$", "-test.count=1") - cmd.Args = append(cmd.Args, args...) - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") - out, _ := cmd.CombinedOutput() - if !re.Match(out) { - t.Errorf("got output:\n%s\nwant matching:\n%s", out, pattern) - } -} - -func TestNow(t *testing.T) { - synctest.Test(t, func(t *testing.T) { - if got, want := time.Now(), time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC); !got.Equal(want) { - t.Errorf("time.Now() = %v, want %v", got, want) - } - }) -} diff --git a/testing/testing/testing.go b/testing/testing/testing.go deleted file mode 100644 index 13327792..00000000 --- a/testing/testing/testing.go +++ /dev/null @@ -1,2730 +0,0 @@ -// Copyright 2009 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 provides support for automated testing of Go packages. -// It is intended to be used in concert with the "go test" command, which automates -// execution of any function of the form -// -// func TestXxx(*testing.T) -// -// where Xxx does not start with a lowercase letter. The function name -// serves to identify the test routine. -// -// Within these functions, use [T.Error], [T.Fail] or related methods to signal failure. -// -// To write a new test suite, create a file that -// contains the TestXxx functions as described here, -// and give that file a name ending in "_test.go". -// The file will be excluded from regular -// package builds but will be included when the "go test" command is run. -// -// The test file can be in the same package as the one being tested, -// or in a corresponding package with the suffix "_test". -// -// If the test file is in the same package, it may refer to unexported -// identifiers within the package, as in this example: -// -// package abs -// -// import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -// -// func TestAbs(t *testing.T) { -// got := Abs(-1) -// if got != 1 { -// t.Errorf("Abs(-1) = %d; want 1", got) -// } -// } -// -// If the file is in a separate "_test" package, the package being tested -// must be imported explicitly and only its exported identifiers may be used. -// This is known as "black box" testing. -// -// package abs_test -// -// import ( -// testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -// -// "path_to_pkg/abs" -// ) -// -// func TestAbs(t *testing.T) { -// got := abs.Abs(-1) -// if got != 1 { -// t.Errorf("Abs(-1) = %d; want 1", got) -// } -// } -// -// For more detail, run [go help test] and [go help testflag]. -// -// # Benchmarks -// -// Functions of the form -// -// func BenchmarkXxx(*testing.B) -// -// are considered benchmarks, and are executed by the "go test" command when -// its -bench flag is provided. Benchmarks are run sequentially. -// -// For a description of the testing flags, see [go help testflag]. -// -// A sample benchmark function looks like this: -// -// func BenchmarkRandInt(b *testing.B) { -// for b.Loop() { -// rand.Int() -// } -// } -// -// The output -// -// BenchmarkRandInt-8 68453040 17.8 ns/op -// -// means that the body of the loop ran 68453040 times at a speed of 17.8 ns per loop. -// -// Only the body of the loop is timed, so benchmarks may do expensive -// setup before calling b.Loop, which will not be counted toward the -// benchmark measurement: -// -// func BenchmarkBigLen(b *testing.B) { -// big := NewBig() -// for b.Loop() { -// big.Len() -// } -// } -// -// If a benchmark needs to test performance in a parallel setting, it may use -// the RunParallel helper function; such benchmarks are intended to be used with -// the go test -cpu flag: -// -// func BenchmarkTemplateParallel(b *testing.B) { -// templ := template.Must(template.New("test").Parse("Hello, {{.}}!")) -// b.RunParallel(func(pb *testing.PB) { -// var buf bytes.Buffer -// for pb.Next() { -// buf.Reset() -// templ.Execute(&buf, "World") -// } -// }) -// } -// -// A detailed specification of the benchmark results format is given -// in https://go.dev/design/14313-benchmark-format. -// -// There are standard tools for working with benchmark results at -// [golang.org/x/perf/cmd]. -// In particular, [golang.org/x/perf/cmd/benchstat] performs -// statistically robust A/B comparisons. -// -// # b.N-style benchmarks -// -// Prior to the introduction of [B.Loop], benchmarks were written in a -// different style using B.N. For example: -// -// func BenchmarkRandInt(b *testing.B) { -// for range b.N { -// rand.Int() -// } -// } -// -// In this style of benchmark, the benchmark function must run -// the target code b.N times. The benchmark function is called -// multiple times with b.N adjusted until the benchmark function -// lasts long enough to be timed reliably. This also means any setup -// done before the loop may be run several times. -// -// If a benchmark needs some expensive setup before running, the timer -// should be explicitly reset: -// -// func BenchmarkBigLen(b *testing.B) { -// big := NewBig() -// b.ResetTimer() -// for range b.N { -// big.Len() -// } -// } -// -// New benchmarks should prefer using [B.Loop], which is more robust -// and more efficient. -// -// # Examples -// -// The package also runs and verifies example code. Example functions may -// include a concluding line comment that begins with "Output:" and is compared with -// the standard output of the function when the tests are run. (The comparison -// ignores leading and trailing space.) These are examples of an example: -// -// func ExampleHello() { -// fmt.Println("hello") -// // Output: hello -// } -// -// func ExampleSalutations() { -// fmt.Println("hello, and") -// fmt.Println("goodbye") -// // Output: -// // hello, and -// // goodbye -// } -// -// The comment prefix "Unordered output:" is like "Output:", but matches any -// line order: -// -// func ExamplePerm() { -// for _, value := range Perm(5) { -// fmt.Println(value) -// } -// // Unordered output: 4 -// // 2 -// // 1 -// // 3 -// // 0 -// } -// -// Example functions without output comments are compiled but not executed. -// -// The naming convention to declare examples for the package, a function F, a type T and -// method M on type T are: -// -// func Example() { ... } -// func ExampleF() { ... } -// func ExampleT() { ... } -// func ExampleT_M() { ... } -// -// Multiple example functions for a package/type/function/method may be provided by -// appending a distinct suffix to the name. The suffix must start with a -// lower-case letter. -// -// func Example_suffix() { ... } -// func ExampleF_suffix() { ... } -// func ExampleT_suffix() { ... } -// func ExampleT_M_suffix() { ... } -// -// The entire test file is presented as the example when it contains a single -// example function, at least one other function, type, variable, or constant -// declaration, and no test or benchmark functions. -// -// # Fuzzing -// -// 'go test' and the testing package support fuzzing, a testing technique where -// a function is called with randomly generated inputs to find bugs not -// anticipated by unit tests. -// -// Functions of the form -// -// func FuzzXxx(*testing.F) -// -// are considered fuzz tests. -// -// For example: -// -// func FuzzHex(f *testing.F) { -// for _, seed := range [][]byte{{}, {0}, {9}, {0xa}, {0xf}, {1, 2, 3, 4}} { -// f.Add(seed) -// } -// f.Fuzz(func(t *testing.T, in []byte) { -// enc := hex.EncodeToString(in) -// out, err := hex.DecodeString(enc) -// if err != nil { -// t.Fatalf("%v: decode: %v", in, err) -// } -// if !bytes.Equal(in, out) { -// t.Fatalf("%v: not equal after round trip: %v", in, out) -// } -// }) -// } -// -// A fuzz test maintains a seed corpus, or a set of inputs which are run by -// default, and can seed input generation. Seed inputs may be registered by -// calling [F.Add] or by storing files in the directory testdata/fuzz/ -// (where is the name of the fuzz test) within the package containing -// the fuzz test. Seed inputs are optional, but the fuzzing engine may find -// bugs more efficiently when provided with a set of small seed inputs with good -// code coverage. These seed inputs can also serve as regression tests for bugs -// identified through fuzzing. -// -// The function passed to [F.Fuzz] within the fuzz test is considered the fuzz -// target. A fuzz target must accept a [*T] parameter, followed by one or more -// parameters for random inputs. The types of arguments passed to [F.Add] must -// be identical to the types of these parameters. The fuzz target may signal -// that it's found a problem the same way tests do: by calling [T.Fail] (or any -// method that calls it like [T.Error] or [T.Fatal]) or by panicking. -// -// When fuzzing is enabled (by setting the -fuzz flag to a regular expression -// that matches a specific fuzz test), the fuzz target is called with arguments -// generated by repeatedly making random changes to the seed inputs. On -// supported platforms, 'go test' compiles the test executable with fuzzing -// coverage instrumentation. The fuzzing engine uses that instrumentation to -// find and cache inputs that expand coverage, increasing the likelihood of -// finding bugs. If the fuzz target fails for a given input, the fuzzing engine -// writes the inputs that caused the failure to a file in the directory -// testdata/fuzz/ within the package directory. This file later serves as -// a seed input. If the file can't be written at that location (for example, -// because the directory is read-only), the fuzzing engine writes the file to -// the fuzz cache directory within the build cache instead. -// -// When fuzzing is disabled, the fuzz target is called with the seed inputs -// registered with [F.Add] and seed inputs from testdata/fuzz/. In this -// mode, the fuzz test acts much like a regular test, with subtests started -// with [F.Fuzz] instead of [T.Run]. -// -// See https://go.dev/doc/fuzz for documentation about fuzzing. -// -// # Skipping -// -// Tests or benchmarks may be skipped at run time with a call to -// [T.Skip] or [B.Skip]: -// -// func TestTimeConsuming(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// ... -// } -// -// The [T.Skip] method can be used in a fuzz target if the input is invalid, -// but should not be considered a failing input. For example: -// -// func FuzzJSONMarshaling(f *testing.F) { -// f.Fuzz(func(t *testing.T, b []byte) { -// var v interface{} -// if err := json.Unmarshal(b, &v); err != nil { -// t.Skip() -// } -// if _, err := json.Marshal(v); err != nil { -// t.Errorf("Marshal: %v", err) -// } -// }) -// } -// -// # Subtests and Sub-benchmarks -// -// The [T.Run] and [B.Run] methods allow defining subtests and sub-benchmarks, -// without having to define separate functions for each. This enables uses -// like table-driven benchmarks and creating hierarchical tests. -// It also provides a way to share common setup and tear-down code: -// -// func TestFoo(t *testing.T) { -// // -// t.Run("A=1", func(t *testing.T) { ... }) -// t.Run("A=2", func(t *testing.T) { ... }) -// t.Run("B=1", func(t *testing.T) { ... }) -// // -// } -// -// Each subtest and sub-benchmark has a unique name: the combination of the name -// of the top-level test and the sequence of names passed to Run, separated by -// slashes, with an optional trailing sequence number for disambiguation. -// -// The argument to the -run, -bench, and -fuzz command-line flags is an unanchored regular -// expression that matches the test's name. For tests with multiple slash-separated -// elements, such as subtests, the argument is itself slash-separated, with -// expressions matching each name element in turn. Because it is unanchored, an -// empty expression matches any string. -// For example, using "matching" to mean "whose name contains": -// -// go test -run '' # Run all tests. -// go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar". -// go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=". -// go test -run /A=1 # For all top-level tests, run subtests matching "A=1". -// go test -fuzz FuzzFoo # Fuzz the target matching "FuzzFoo" -// -// The -run argument can also be used to run a specific value in the seed -// corpus, for debugging. For example: -// -// go test -run=FuzzFoo/9ddb952d9814 -// -// The -fuzz and -run flags can both be set, in order to fuzz a target but -// skip the execution of all other tests. -// -// Subtests can also be used to control parallelism. A parent test will only -// complete once all of its subtests complete. In this example, all tests are -// run in parallel with each other, and only with each other, regardless of -// other top-level tests that may be defined: -// -// func TestGroupedParallel(t *testing.T) { -// for _, tc := range tests { -// t.Run(tc.Name, func(t *testing.T) { -// t.Parallel() -// ... -// }) -// } -// } -// -// Run does not return until parallel subtests have completed, providing a way -// to clean up after a group of parallel tests: -// -// func TestTeardownParallel(t *testing.T) { -// // This Run will not return until the parallel tests finish. -// t.Run("group", func(t *testing.T) { -// t.Run("Test1", parallelTest1) -// t.Run("Test2", parallelTest2) -// t.Run("Test3", parallelTest3) -// }) -// // -// } -// -// # Main -// -// It is sometimes necessary for a test or benchmark program to do extra setup or teardown -// before or after it executes. It is also sometimes necessary to control -// which code runs on the main thread. To support these and other cases, -// if a test file contains a function: -// -// func TestMain(m *testing.M) -// -// then the generated test will call TestMain(m) instead of running the tests or benchmarks -// directly. TestMain runs in the main goroutine and can do whatever setup -// and teardown is necessary around a call to m.Run. m.Run will return an exit -// code that may be passed to [os.Exit]. If TestMain returns, the test wrapper -// will pass the result of m.Run to [os.Exit] itself. -// -// When TestMain is called, flag.Parse has not been run. If TestMain depends on -// command-line flags, including those of the testing package, it should call -// [flag.Parse] explicitly. Command line flags are always parsed by the time test -// or benchmark functions run. -// -// A simple implementation of TestMain is: -// -// func TestMain(m *testing.M) { -// // call flag.Parse() here if TestMain uses flags -// m.Run() -// } -// -// TestMain is a low-level primitive and should not be necessary for casual -// testing needs, where ordinary test functions suffice. -// -// [go help test]: https://pkg.go.dev/cmd/go#hdr-Test_packages -// [go help testflag]: https://pkg.go.dev/cmd/go#hdr-Testing_flags -package testing - -import ( - "bytes" - "context" - "errors" - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/race" - "io" - "math/rand" - "os" - "path/filepath" - "reflect" - "runtime" - "runtime/debug" - "runtime/trace" - "slices" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - "unicode" - "unicode/utf8" - _ "unsafe" // for linkname -) - -var initRan bool - -var ( - parallelStart atomic.Int64 // number of parallel tests started - parallelStop atomic.Int64 // number of parallel tests stopped -) - -// Init registers testing flags. These flags are automatically registered by -// the "go test" command before running test functions, so Init is only needed -// when calling functions such as Benchmark without using "go test". -// -// Init is not safe to call concurrently. It has no effect if it was already called. -func Init() { - if initRan { - return - } - initRan = true - // The short flag requests that tests run more quickly, but its functionality - // is provided by test writers themselves. The testing package is just its - // home. The all.bash installation script sets it to make installation more - // efficient, but by default the flag is off so a plain "go test" will do a - // full test of the package. - short = flag.Bool("test.short", false, "run smaller test suite to save time") - - // The failfast flag requests that test execution stop after the first test failure. - failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure") - - // The directory in which to create profile files and the like. When run from - // "go test", the binary always runs in the source directory for the package; - // this flag lets "go test" tell the binary to write the files in the directory where - // the "go test" command is run. - outputDir = flag.String("test.outputdir", "", "write profiles to `dir`") - // Report as tests are run; default is silent for success. - flag.Var(&chatty, "test.v", "verbose: print additional output") - count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times") - coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`") - gocoverdir = flag.String("test.gocoverdir", "", "write coverage intermediate files to this directory") - matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit") - match = flag.String("test.run", "", "run only tests and examples matching `regexp`") - skip = flag.String("test.skip", "", "do not list or run tests matching `regexp`") - memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`") - memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)") - cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`") - blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`") - blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)") - mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution") - mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()") - panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)") - traceFile = flag.String("test.trace", "", "write an execution trace to `file`") - timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)") - cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with") - parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel") - testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)") - shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks") - fullPath = flag.Bool("test.fullpath", false, "show full file names in error messages") - - initBenchmarkFlags() - initFuzzFlags() -} - -var ( - // Flags, registered during Init. - short *bool - failFast *bool - outputDir *string - chatty chattyFlag - count *uint - coverProfile *string - gocoverdir *string - matchList *string - match *string - skip *string - memProfile *string - memProfileRate *int - cpuProfile *string - blockProfile *string - blockProfileRate *int - mutexProfile *string - mutexProfileFraction *int - panicOnExit0 *bool - traceFile *string - timeout *time.Duration - cpuListStr *string - parallel *int - shuffle *string - testlog *string - fullPath *bool - - haveExamples bool // are there examples? - - cpuList []int - testlogFile *os.File - - numFailed atomic.Uint32 // number of test failures - - running sync.Map // map[string]time.Time of running, unpaused tests -) - -type chattyFlag struct { - on bool // -v is set in some form - json bool // -v=test2json is set, to make output better for test2json -} - -func (*chattyFlag) IsBoolFlag() bool { return true } - -func (f *chattyFlag) Set(arg string) error { - switch arg { - default: - return fmt.Errorf("invalid flag -test.v=%s", arg) - case "true", "test2json": - f.on = true - f.json = arg == "test2json" - case "false": - f.on = false - f.json = false - } - return nil -} - -func (f *chattyFlag) String() string { - if f.json { - return "test2json" - } - if f.on { - return "true" - } - return "false" -} - -func (f *chattyFlag) Get() any { - if f.json { - return "test2json" - } - return f.on -} - -const marker = byte(0x16) // ^V for framing - -func (f *chattyFlag) prefix() string { - if f.json { - return string(marker) - } - return "" -} - -type chattyPrinter struct { - w io.Writer - lastNameMu sync.Mutex // guards lastName - lastName string // last printed test name in chatty mode - json bool // -v=json output mode -} - -func newChattyPrinter(w io.Writer) *chattyPrinter { - return &chattyPrinter{w: w, json: chatty.json} -} - -// prefix is like chatty.prefix but using p.json instead of chatty.json. -// Using p.json allows tests to check the json behavior without modifying -// the global variable. For convenience, we allow p == nil and treat -// that as not in json mode (because it's not chatty at all). -func (p *chattyPrinter) prefix() string { - if p != nil && p.json { - return string(marker) - } - return "" -} - -// Updatef prints a message about the status of the named test to w. -// -// The formatted message must include the test name itself. -func (p *chattyPrinter) Updatef(testName, format string, args ...any) { - p.lastNameMu.Lock() - defer p.lastNameMu.Unlock() - - // Since the message already implies an association with a specific new test, - // we don't need to check what the old test name was or log an extra NAME line - // for it. (We're updating it anyway, and the current message already includes - // the test name.) - p.lastName = testName - fmt.Fprintf(p.w, p.prefix()+format, args...) -} - -// Printf prints a message, generated by the named test, that does not -// necessarily mention that tests's name itself. -func (p *chattyPrinter) Printf(testName, format string, args ...any) { - p.lastNameMu.Lock() - defer p.lastNameMu.Unlock() - - if p.lastName == "" { - p.lastName = testName - } else if p.lastName != testName { - fmt.Fprintf(p.w, "%s=== NAME %s\n", p.prefix(), testName) - p.lastName = testName - } - - fmt.Fprintf(p.w, format, args...) -} - -// The maximum number of stack frames to go through when skipping helper functions for -// the purpose of decorating log messages. -const maxStackLen = 50 - -// common holds the elements common between T and B and -// captures common methods such as Errorf. -type common struct { - mu sync.RWMutex // guards this group of fields - output []byte // Output generated by test or benchmark. - w io.Writer // For flushToParent. - o *outputWriter // Writes output. - ran bool // Test or benchmark (or one of its subtests) was executed. - failed bool // Test or benchmark has failed. - skipped bool // Test or benchmark has been skipped. - done bool // Test is finished and all subtests have completed. - helperPCs map[uintptr]struct{} // functions to be skipped when writing file/line info - helperNames map[string]struct{} // helperPCs converted to function names - cleanups []func() // optional functions to be called at the end of the test - cleanupName string // Name of the cleanup function. - cleanupPc []uintptr // The stack trace at the point where Cleanup was called. - finished bool // Test function has completed. - inFuzzFn bool // Whether the fuzz target, if this is one, is running. - isSynctest bool - - chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set. - bench bool // Whether the current test is a benchmark. - hasSub atomic.Bool // whether there are sub-benchmarks. - cleanupStarted atomic.Bool // Registered cleanup callbacks have started to execute - runner string // Function name of tRunner running the test. - isParallel bool // Whether the test is parallel. - - parent *common - level int // Nesting depth of test or benchmark. - creator []uintptr // If level > 0, the stack trace at the point where the parent called t.Run. - name string // Name of test or benchmark. - start highPrecisionTime // Time test or benchmark started - duration time.Duration - barrier chan bool // To signal parallel subtests they may start. Nil when T.Parallel is not present (B) or not usable (when fuzzing). - signal chan bool // To signal a test is done. - sub []*T // Queue of subtests to be run in parallel. - - lastRaceErrors atomic.Int64 // Max value of race.Errors seen during the test or its subtests. - raceErrorLogged atomic.Bool - - tempDirMu sync.Mutex - tempDir string - tempDirErr error - tempDirSeq int32 - - ctx context.Context - cancelCtx context.CancelFunc -} - -// Short reports whether the -test.short flag is set. -func Short() bool { - if short == nil { - panic("testing: Short called before Init") - } - // Catch code that calls this from TestMain without first calling flag.Parse. - if !flag.Parsed() { - panic("testing: Short called before Parse") - } - - return *short -} - -// testBinary is set by cmd/go to "1" if this is a binary built by "go test". -// The value is set to "1" by a -X option to cmd/link. We assume that -// because this is possible, the compiler will not optimize testBinary -// into a constant on the basis that it is an unexported package-scope -// variable that is never changed. If the compiler ever starts implementing -// such an optimization, we will need some technique to mark this variable -// as "changed by a cmd/link -X option". -var testBinary = "0" - -// Testing reports whether the current code is being run in a test. -// This will report true in programs created by "go test", -// false in programs created by "go build". -func Testing() bool { - return testBinary == "1" -} - -// CoverMode reports what the test coverage mode is set to. The -// values are "set", "count", or "atomic". The return value will be -// empty if test coverage is not enabled. -func CoverMode() string { - return cover.mode -} - -// Verbose reports whether the -test.v flag is set. -func Verbose() bool { - // Same as in Short. - if !flag.Parsed() { - panic("testing: Verbose called before Parse") - } - return chatty.on -} - -func (c *common) checkFuzzFn(name string) { - if c.inFuzzFn { - panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name)) - } -} - -// frameSkip searches, starting after skip frames, for the first caller frame -// in a function not marked as a helper and returns that frame. -// The search stops if it finds a tRunner function that -// was the entry point into the test and the test is not a subtest. -// This function must be called with c.mu held. -func (c *common) frameSkip(skip int) runtime.Frame { - // If the search continues into the parent test, we'll have to hold - // its mu temporarily. If we then return, we need to unlock it. - shouldUnlock := false - defer func() { - if shouldUnlock { - c.mu.Unlock() - } - }() - var pc [maxStackLen]uintptr - // Skip two extra frames to account for this function - // and runtime.Callers itself. - n := runtime.Callers(skip+2, pc[:]) - if n == 0 { - panic("testing: zero callers found") - } - frames := runtime.CallersFrames(pc[:n]) - var firstFrame, prevFrame, frame runtime.Frame - for more := true; more; prevFrame = frame { - frame, more = frames.Next() - if frame.Function == "runtime.gopanic" { - continue - } - if frame.Function == c.cleanupName { - frames = runtime.CallersFrames(c.cleanupPc) - continue - } - if firstFrame.PC == 0 { - firstFrame = frame - } - if frame.Function == c.runner { - // We've gone up all the way to the tRunner calling - // the test function (so the user must have - // called tb.Helper from inside that test function). - // If this is a top-level test, only skip up to the test function itself. - // If we're in a subtest, continue searching in the parent test, - // starting from the point of the call to Run which created this subtest. - if c.level > 1 { - frames = runtime.CallersFrames(c.creator) - parent := c.parent - // We're no longer looking at the current c after this point, - // so we should unlock its mu, unless it's the original receiver, - // in which case our caller doesn't expect us to do that. - if shouldUnlock { - c.mu.Unlock() - } - c = parent - // Remember to unlock c.mu when we no longer need it, either - // because we went up another nesting level, or because we - // returned. - shouldUnlock = true - c.mu.Lock() - continue - } - return prevFrame - } - // If more helper PCs have been added since we last did the conversion - if c.helperNames == nil { - c.helperNames = make(map[string]struct{}) - for pc := range c.helperPCs { - c.helperNames[pcToName(pc)] = struct{}{} - } - } - if _, ok := c.helperNames[frame.Function]; !ok { - // Found a frame that wasn't inside a helper function. - return frame - } - } - return firstFrame -} - -// flushToParent writes c.output to the parent after first writing the header -// with the given format and arguments. -func (c *common) flushToParent(testName, format string, args ...any) { - p := c.parent - p.mu.Lock() - defer p.mu.Unlock() - - c.mu.Lock() - defer c.mu.Unlock() - - if len(c.output) > 0 { - // Add the current c.output to the print, - // and then arrange for the print to replace c.output. - // (This displays the logged output after the --- FAIL line.) - format += "%s" - args = append(args[:len(args):len(args)], c.output) - c.output = c.output[:0] - } - - if c.chatty != nil && (p.w == c.chatty.w || c.chatty.json) { - // We're flushing to the actual output, so track that this output is - // associated with a specific test (and, specifically, that the next output - // is *not* associated with that test). - // - // Moreover, if c.output is non-empty it is important that this write be - // atomic with respect to the output of other tests, so that we don't end up - // with confusing '=== NAME' lines in the middle of our '--- PASS' block. - // Neither humans nor cmd/test2json can parse those easily. - // (See https://go.dev/issue/40771.) - // - // If test2json is used, we never flush to parent tests, - // so that the json stream shows subtests as they finish. - // (See https://go.dev/issue/29811.) - c.chatty.Updatef(testName, format, args...) - } else { - // We're flushing to the output buffer of the parent test, which will - // itself follow a test-name header when it is finally flushed to stdout. - fmt.Fprintf(p.w, c.chatty.prefix()+format, args...) - } -} - -type indenter struct { - c *common -} - -const indent = " " - -func (w indenter) Write(b []byte) (n int, err error) { - n = len(b) - for len(b) > 0 { - end := bytes.IndexByte(b, '\n') - if end == -1 { - end = len(b) - } else { - end++ - } - // An indent of 4 spaces will neatly align the dashes with the status - // indicator of the parent. - line := b[:end] - if line[0] == marker { - w.c.output = append(w.c.output, marker) - line = line[1:] - } - w.c.output = append(w.c.output, indent...) - w.c.output = append(w.c.output, line...) - b = b[end:] - } - return -} - -// fmtDuration returns a string representing d in the form "87.00s". -func fmtDuration(d time.Duration) string { - return fmt.Sprintf("%.2fs", d.Seconds()) -} - -// TB is the interface common to [T], [B], and [F]. -type TB interface { - Attr(key, value string) - Cleanup(func()) - Error(args ...any) - Errorf(format string, args ...any) - Fail() - FailNow() - Failed() bool - Fatal(args ...any) - Fatalf(format string, args ...any) - Helper() - Log(args ...any) - Logf(format string, args ...any) - Name() string - Setenv(key, value string) - Chdir(dir string) - Skip(args ...any) - SkipNow() - Skipf(format string, args ...any) - Skipped() bool - TempDir() string - Context() context.Context - Output() io.Writer - - // A private method to prevent users implementing the - // interface and so future additions to it will not - // violate Go 1 compatibility. - private() -} - -var ( - _ TB = (*T)(nil) - _ TB = (*B)(nil) -) - -// T is a type passed to Test functions to manage test state and support formatted test logs. -// -// A test ends when its Test function returns or calls any of the methods -// [T.FailNow], [T.Fatal], [T.Fatalf], [T.SkipNow], [T.Skip], or [T.Skipf]. Those methods, as well as -// the [T.Parallel] method, must be called only from the goroutine running the -// Test function. -// -// The other reporting methods, such as the variations of [T.Log] and [T.Error], -// may be called simultaneously from multiple goroutines. -type T struct { - common - denyParallel bool - tstate *testState // For running tests and subtests. -} - -func (c *common) private() {} - -// Name returns the name of the running (sub-) test or benchmark. -// -// The name will include the name of the test along with the names of -// any nested sub-tests. If two sibling sub-tests have the same name, -// Name will append a suffix to guarantee the returned name is unique. -func (c *common) Name() string { - return c.name -} - -func (c *common) setRan() { - if c.parent != nil { - c.parent.setRan() - } - c.mu.Lock() - defer c.mu.Unlock() - c.ran = true -} - -// Fail marks the function as having failed but continues execution. -func (c *common) Fail() { - if c.parent != nil { - c.parent.Fail() - } - c.mu.Lock() - defer c.mu.Unlock() - // c.done needs to be locked to synchronize checks to c.done in parent tests. - if c.done { - panic("Fail in goroutine after " + c.name + " has completed") - } - c.failed = true -} - -// Failed reports whether the function has failed. -func (c *common) Failed() bool { - c.mu.RLock() - defer c.mu.RUnlock() - - if !c.done && int64(race.Errors()) > c.lastRaceErrors.Load() { - c.mu.RUnlock() - c.checkRaces() - c.mu.RLock() - } - - return c.failed -} - -// FailNow marks the function as having failed and stops its execution -// by calling [runtime.Goexit] (which then runs all deferred calls in the -// current goroutine). -// Execution will continue at the next test or benchmark. -// FailNow must be called from the goroutine running the -// test or benchmark function, not from other goroutines -// created during the test. Calling FailNow does not stop -// those other goroutines. -func (c *common) FailNow() { - c.checkFuzzFn("FailNow") - c.Fail() - - // Calling runtime.Goexit will exit the goroutine, which - // will run the deferred functions in this goroutine, - // which will eventually run the deferred lines in tRunner, - // which will signal to the test loop that this test is done. - // - // A previous version of this code said: - // - // c.duration = ... - // c.signal <- c.self - // runtime.Goexit() - // - // This previous version duplicated code (those lines are in - // tRunner no matter what), but worse the goroutine teardown - // implicit in runtime.Goexit was not guaranteed to complete - // before the test exited. If a test deferred an important cleanup - // function (like removing temporary files), there was no guarantee - // it would run on a test failure. Because we send on c.signal during - // a top-of-stack deferred function now, we know that the send - // only happens after any other stacked defers have completed. - c.mu.Lock() - c.finished = true - c.mu.Unlock() - runtime.Goexit() -} - -// log generates the output. It is always at the same stack depth. log inserts -// indentation and the final newline if necessary. It prefixes the string -// with the file and line of the call site. -func (c *common) log(s string) { - s = strings.TrimSuffix(s, "\n") - - // Second and subsequent lines are indented 4 spaces. This is in addition to - // the indentation provided by outputWriter. - s = strings.ReplaceAll(s, "\n", "\n"+indent) - s += "\n" - - n := c.destination() - if n == nil { - // The test and all its parents are done. The log cannot be output. - panic("Log in goroutine after " + c.name + " has completed: " + s) - } - - // Prefix with the call site. It is located by skipping 3 functions: - // callSite + log + public function - s = n.callSite(3) + s - - // Output buffered logs. - n.flushPartial() - - n.o.Write([]byte(s)) -} - -// destination selects the test to which output should be appended. It returns the -// test if it is incomplete. Otherwise, it finds its closest incomplete parent. -func (c *common) destination() *common { - c.mu.Lock() - defer c.mu.Unlock() - - if !c.done && !c.isSynctest { - return c - } - for parent := c.parent; parent != nil; parent = parent.parent { - parent.mu.Lock() - defer parent.mu.Unlock() - if !parent.done { - return parent - } - } - return nil -} - -// callSite retrieves and formats the file and line of the call site. -func (c *common) callSite(skip int) string { - c.mu.Lock() - defer c.mu.Unlock() - - frame := c.frameSkip(skip) - file := frame.File - line := frame.Line - if file != "" { - if *fullPath { - // If relative path, truncate file name at last file name separator. - } else { - file = filepath.Base(file) - } - - // Replace _codspeed.go with _test.go for better user experience - if strings.HasSuffix(file, "_codspeed.go") { - file = strings.TrimSuffix(file, "_codspeed.go") + "_test.go" - } - } else { - file = "???" - } - if line == 0 { - line = 1 - } - - return fmt.Sprintf("%s:%d: ", file, line) -} - -// flushPartial checks the buffer for partial logs and outputs them. -func (c *common) flushPartial() { - partial := func() bool { - c.mu.Lock() - defer c.mu.Unlock() - return (c.o != nil) && (len(c.o.partial) > 0) - } - - if partial() { - c.o.Write([]byte("\n")) - } -} - -// Output returns a Writer that writes to the same test output stream as TB.Log. -// The output is indented like TB.Log lines, but Output does not -// add source locations or newlines. The output is internally line -// buffered, and a call to TB.Log or the end of the test will implicitly -// flush the buffer, followed by a newline. After a test function and all its -// parents return, neither Output nor the Write method may be called. -func (c *common) Output() io.Writer { - c.checkFuzzFn("Output") - n := c.destination() - if n == nil { - panic("Output called after " + c.name + " has completed") - } - return n.o -} - -// setOutputWriter initializes an outputWriter and sets it as a common field. -func (c *common) setOutputWriter() { - c.o = &outputWriter{c: c} -} - -// outputWriter buffers, formats and writes log messages. -type outputWriter struct { - c *common - partial []byte // incomplete ('\n'-free) suffix of last Write -} - -// Write writes a log message to the test's output stream, properly formatted and -// indented. It may not be called after a test function and all its parents return. -func (o *outputWriter) Write(p []byte) (int, error) { - // o can be nil if this is called from a top-level *TB that is no longer active. - // Just ignore the message in that case. - if o == nil || o.c == nil { - return 0, nil - } - if o.c.destination() == nil { - panic("Write called after " + o.c.name + " has completed") - } - - o.c.mu.Lock() - defer o.c.mu.Unlock() - - // The last element is a partial line. - lines := bytes.SplitAfter(p, []byte("\n")) - last := len(lines) - 1 // Inv: 0 <= last - for i, line := range lines[:last] { - // Emit partial line from previous call. - if i == 0 && len(o.partial) > 0 { - line = slices.Concat(o.partial, line) - o.partial = o.partial[:0] - } - o.writeLine(line) - } - // Save partial line for next call. - o.partial = append(o.partial, lines[last]...) - - return len(p), nil -} - -// writeLine generates the output for a given line. -func (o *outputWriter) writeLine(b []byte) { - if !o.c.done && (o.c.chatty != nil) { - if o.c.bench { - // Benchmarks don't print === CONT, so we should skip the test - // printer and just print straight to stdout. - fmt.Printf("%s%s", indent, b) - } else { - o.c.chatty.Printf(o.c.name, "%s%s", indent, b) - } - return - } - o.c.output = append(o.c.output, indent...) - o.c.output = append(o.c.output, b...) -} - -// Log formats its arguments using default formatting, analogous to [fmt.Println], -// and records the text in the error log. For tests, the text will be printed only if -// the test fails or the -test.v flag is set. For benchmarks, the text is always -// printed to avoid having performance depend on the value of the -test.v flag. -// It is an error to call Log after a test or benchmark returns. -func (c *common) Log(args ...any) { - c.checkFuzzFn("Log") - c.log(fmt.Sprintln(args...)) -} - -// Logf formats its arguments according to the format, analogous to [fmt.Printf], and -// records the text in the error log. A final newline is added if not provided. For -// tests, the text will be printed only if the test fails or the -test.v flag is -// set. For benchmarks, the text is always printed to avoid having performance -// depend on the value of the -test.v flag. -// It is an error to call Logf after a test or benchmark returns. -func (c *common) Logf(format string, args ...any) { - c.checkFuzzFn("Logf") - c.log(fmt.Sprintf(format, args...)) -} - -// Error is equivalent to Log followed by Fail. -func (c *common) Error(args ...any) { - c.checkFuzzFn("Error") - c.log(fmt.Sprintln(args...)) - c.Fail() -} - -// Errorf is equivalent to Logf followed by Fail. -func (c *common) Errorf(format string, args ...any) { - c.checkFuzzFn("Errorf") - c.log(fmt.Sprintf(format, args...)) - c.Fail() -} - -// Fatal is equivalent to Log followed by FailNow. -func (c *common) Fatal(args ...any) { - c.checkFuzzFn("Fatal") - c.log(fmt.Sprintln(args...)) - c.FailNow() -} - -// Fatalf is equivalent to Logf followed by FailNow. -func (c *common) Fatalf(format string, args ...any) { - c.checkFuzzFn("Fatalf") - c.log(fmt.Sprintf(format, args...)) - c.FailNow() -} - -// Skip is equivalent to Log followed by SkipNow. -func (c *common) Skip(args ...any) { - c.checkFuzzFn("Skip") - c.log(fmt.Sprintln(args...)) - c.SkipNow() -} - -// Skipf is equivalent to Logf followed by SkipNow. -func (c *common) Skipf(format string, args ...any) { - c.checkFuzzFn("Skipf") - c.log(fmt.Sprintf(format, args...)) - c.SkipNow() -} - -// SkipNow marks the test as having been skipped and stops its execution -// by calling [runtime.Goexit]. -// If a test fails (see Error, Errorf, Fail) and is then skipped, -// it is still considered to have failed. -// Execution will continue at the next test or benchmark. See also FailNow. -// SkipNow must be called from the goroutine running the test, not from -// other goroutines created during the test. Calling SkipNow does not stop -// those other goroutines. -func (c *common) SkipNow() { - c.checkFuzzFn("SkipNow") - c.mu.Lock() - c.skipped = true - c.finished = true - c.mu.Unlock() - runtime.Goexit() -} - -// Skipped reports whether the test was skipped. -func (c *common) Skipped() bool { - c.mu.RLock() - defer c.mu.RUnlock() - return c.skipped -} - -// Helper marks the calling function as a test helper function. -// When printing file and line information, that function will be skipped. -// Helper may be called simultaneously from multiple goroutines. -func (c *common) Helper() { - if c.isSynctest { - c = c.parent - } - c.mu.Lock() - defer c.mu.Unlock() - if c.helperPCs == nil { - c.helperPCs = make(map[uintptr]struct{}) - } - // repeating code from callerName here to save walking a stack frame - var pc [1]uintptr - n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper - if n == 0 { - panic("testing: zero callers found") - } - if _, found := c.helperPCs[pc[0]]; !found { - c.helperPCs[pc[0]] = struct{}{} - c.helperNames = nil // map will be recreated next time it is needed - } -} - -// Cleanup registers a function to be called when the test (or subtest) and all its -// subtests complete. Cleanup functions will be called in last added, -// first called order. -func (c *common) Cleanup(f func()) { - c.checkFuzzFn("Cleanup") - var pc [maxStackLen]uintptr - // Skip two extra frames to account for this function and runtime.Callers itself. - n := runtime.Callers(2, pc[:]) - cleanupPc := pc[:n] - - fn := func() { - defer func() { - c.mu.Lock() - defer c.mu.Unlock() - c.cleanupName = "" - c.cleanupPc = nil - }() - - name := callerName(0) - c.mu.Lock() - c.cleanupName = name - c.cleanupPc = cleanupPc - c.mu.Unlock() - - f() - } - - c.mu.Lock() - defer c.mu.Unlock() - c.cleanups = append(c.cleanups, fn) -} - -// TempDir returns a temporary directory for the test to use. -// The directory is automatically removed when the test and -// all its subtests complete. -// Each subsequent call to TempDir returns a unique directory; -// if the directory creation fails, TempDir terminates the test by calling Fatal. -func (c *common) TempDir() string { - c.checkFuzzFn("TempDir") - // Use a single parent directory for all the temporary directories - // created by a test, each numbered sequentially. - c.tempDirMu.Lock() - var nonExistent bool - if c.tempDir == "" { // Usually the case with js/wasm - nonExistent = true - } else { - _, err := os.Stat(c.tempDir) - nonExistent = os.IsNotExist(err) - if err != nil && !nonExistent { - c.Fatalf("TempDir: %v", err) - } - } - - if nonExistent { - c.Helper() - - pattern := c.Name() - // Limit length of file names on disk. - // Invalid runes from slicing are dropped by strings.Map below. - pattern = pattern[:min(len(pattern), 64)] - - // Drop unusual characters (such as path separators or - // characters interacting with globs) from the directory name to - // avoid surprising os.MkdirTemp behavior. - mapper := func(r rune) rune { - if r < utf8.RuneSelf { - const allowed = "!#$%&()+,-.=@^_{}~ " - if '0' <= r && r <= '9' || - 'a' <= r && r <= 'z' || - 'A' <= r && r <= 'Z' { - return r - } - if strings.ContainsRune(allowed, r) { - return r - } - } else if unicode.IsLetter(r) || unicode.IsNumber(r) { - return r - } - return -1 - } - pattern = strings.Map(mapper, pattern) - c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern) - if c.tempDirErr == nil { - c.Cleanup(func() { - if err := removeAll(c.tempDir); err != nil { - c.Errorf("TempDir RemoveAll cleanup: %v", err) - } - }) - } - } - - if c.tempDirErr == nil { - c.tempDirSeq++ - } - seq := c.tempDirSeq - c.tempDirMu.Unlock() - - if c.tempDirErr != nil { - c.Fatalf("TempDir: %v", c.tempDirErr) - } - - dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq) - if err := os.Mkdir(dir, 0o777); err != nil { - c.Fatalf("TempDir: %v", err) - } - return dir -} - -// removeAll is like os.RemoveAll, but retries Windows "Access is denied." -// errors up to an arbitrary timeout. -// -// Those errors have been known to occur spuriously on at least the -// windows-amd64-2012 builder (https://go.dev/issue/50051), and can only occur -// legitimately if the test leaves behind a temp file that either is still open -// or the test otherwise lacks permission to delete. In the case of legitimate -// failures, a failing test may take a bit longer to fail, but once the test is -// fixed the extra latency will go away. -func removeAll(path string) error { - const arbitraryTimeout = 2 * time.Second - var ( - start time.Time - nextSleep = 1 * time.Millisecond - ) - for { - err := os.RemoveAll(path) - if !isWindowsRetryable(err) { - return err - } - if start.IsZero() { - start = time.Now() - } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout { - return err - } - time.Sleep(nextSleep) - nextSleep += time.Duration(rand.Int63n(int64(nextSleep))) - } -} - -// Setenv calls [os.Setenv] and uses Cleanup to -// restore the environment variable to its original value -// after the test. -// -// Because Setenv affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (c *common) Setenv(key, value string) { - c.checkFuzzFn("Setenv") - prevValue, ok := os.LookupEnv(key) - - if err := os.Setenv(key, value); err != nil { - c.Fatalf("cannot set environment variable: %v", err) - } - - if ok { - c.Cleanup(func() { - os.Setenv(key, prevValue) - }) - } else { - c.Cleanup(func() { - os.Unsetenv(key) - }) - } -} - -// Chdir calls [os.Chdir] and uses Cleanup to restore the current -// working directory to its original value after the test. On Unix, it -// also sets PWD environment variable for the duration of the test. -// -// Because Chdir affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (c *common) Chdir(dir string) { - c.checkFuzzFn("Chdir") - oldwd, err := os.Open(".") - if err != nil { - c.Fatal(err) - } - if err := os.Chdir(dir); err != nil { - c.Fatal(err) - } - // On POSIX platforms, PWD represents “an absolute pathname of the - // current working directory.” Since we are changing the working - // directory, we should also set or update PWD to reflect that. - switch runtime.GOOS { - case "windows", "plan9": - // Windows and Plan 9 do not use the PWD variable. - default: - if !filepath.IsAbs(dir) { - dir, err = os.Getwd() - if err != nil { - c.Fatal(err) - } - } - c.Setenv("PWD", dir) - } - c.Cleanup(func() { - err := oldwd.Chdir() - oldwd.Close() - if err != nil { - // It's not safe to continue with tests if we can't - // get back to the original working directory. Since - // we are holding a dirfd, this is highly unlikely. - panic("testing.Chdir: " + err.Error()) - } - }) -} - -// Context returns a context that is canceled just before -// Cleanup-registered functions are called. -// -// Cleanup functions can wait for any resources -// that shut down on [context.Context.Done] before the test or benchmark completes. -func (c *common) Context() context.Context { - c.checkFuzzFn("Context") - return c.ctx -} - -// Attr emits a test attribute associated with this test. -// -// The key must not contain whitespace. -// The value must not contain newlines or carriage returns. -// -// The meaning of different attribute keys is left up to -// continuous integration systems and test frameworks. -// -// Test attributes are emitted immediately in the test log, -// but they are intended to be treated as unordered. -func (c *common) Attr(key, value string) { - if strings.ContainsFunc(key, unicode.IsSpace) { - c.Errorf("disallowed whitespace in attribute key %q", key) - return - } - if strings.ContainsAny(value, "\r\n") { - c.Errorf("disallowed newline in attribute value %q", value) - return - } - if c.chatty == nil { - return - } - c.chatty.Updatef(c.name, "=== ATTR %s %v %v\n", c.name, key, value) -} - -// panicHandling controls the panic handling used by runCleanup. -type panicHandling int - -const ( - normalPanic panicHandling = iota - recoverAndReturnPanic -) - -// runCleanup is called at the end of the test. -// If ph is recoverAndReturnPanic, it will catch panics, and return the -// recovered value if any. -func (c *common) runCleanup(ph panicHandling) (panicVal any) { - c.cleanupStarted.Store(true) - defer c.cleanupStarted.Store(false) - - if ph == recoverAndReturnPanic { - defer func() { - panicVal = recover() - }() - } - - // Make sure that if a cleanup function panics, - // we still run the remaining cleanup functions. - defer func() { - c.mu.Lock() - recur := len(c.cleanups) > 0 - c.mu.Unlock() - if recur { - c.runCleanup(normalPanic) - } - }() - - if c.cancelCtx != nil { - c.cancelCtx() - } - - for { - var cleanup func() - c.mu.Lock() - if len(c.cleanups) > 0 { - last := len(c.cleanups) - 1 - cleanup = c.cleanups[last] - c.cleanups = c.cleanups[:last] - } - c.mu.Unlock() - if cleanup == nil { - return nil - } - cleanup() - } -} - -// resetRaces updates c.parent's count of data race errors (or the global count, -// if c has no parent), and updates c.lastRaceErrors to match. -// -// Any races that occurred prior to this call to resetRaces will -// not be attributed to c. -func (c *common) resetRaces() { - if c.parent == nil { - c.lastRaceErrors.Store(int64(race.Errors())) - } else { - c.lastRaceErrors.Store(c.parent.checkRaces()) - } -} - -// checkRaces checks whether the global count of data race errors has increased -// since c's count was last reset. -// -// If so, it marks c as having failed due to those races (logging an error for -// the first such race), and updates the race counts for the parents of c so -// that if they are currently suspended (such as in a call to T.Run) they will -// not log separate errors for the race(s). -// -// Note that multiple tests may be marked as failed due to the same race if they -// are executing in parallel. -func (c *common) checkRaces() (raceErrors int64) { - raceErrors = int64(race.Errors()) - for { - last := c.lastRaceErrors.Load() - if raceErrors <= last { - // All races have already been reported. - return raceErrors - } - if c.lastRaceErrors.CompareAndSwap(last, raceErrors) { - break - } - } - - if c.raceErrorLogged.CompareAndSwap(false, true) { - // This is the first race we've encountered for this test. - // Mark the test as failed, and log the reason why only once. - // (Note that the race detector itself will still write a goroutine - // dump for any further races it detects.) - c.Errorf("race detected during execution of test") - } - - // Update the parent(s) of this test so that they don't re-report the race. - parent := c.parent - for parent != nil { - for { - last := parent.lastRaceErrors.Load() - if raceErrors <= last { - // This race was already reported by another (likely parallel) subtest. - return raceErrors - } - if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) { - break - } - } - parent = parent.parent - } - - return raceErrors -} - -// callerName gives the function name (qualified with a package path) -// for the caller after skip frames (where 0 means the current function). -func callerName(skip int) string { - var pc [1]uintptr - n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName - if n == 0 { - panic("testing: zero callers found") - } - return pcToName(pc[0]) -} - -func pcToName(pc uintptr) string { - pcs := []uintptr{pc} - frames := runtime.CallersFrames(pcs) - frame, _ := frames.Next() - return frame.Function -} - -const parallelConflict = `testing: test using t.Setenv or t.Chdir can not use t.Parallel` - -// Parallel signals that this test is to be run in parallel with (and only with) -// other parallel tests. When a test is run multiple times due to use of -// -test.count or -test.cpu, multiple instances of a single test never run in -// parallel with each other. -func (t *T) Parallel() { - if t.isParallel { - panic("testing: t.Parallel called multiple times") - } - if t.isSynctest { - panic("testing: t.Parallel called inside synctest bubble") - } - if t.denyParallel { - panic(parallelConflict) - } - if t.parent.barrier == nil { - // T.Parallel has no effect when fuzzing. - // Multiple processes may run in parallel, but only one input can run at a - // time per process so we can attribute crashes to specific inputs. - return - } - - t.isParallel = true - - // We don't want to include the time we spend waiting for serial tests - // in the test duration. Record the elapsed time thus far and reset the - // timer afterwards. - t.duration += highPrecisionTimeSince(t.start) - - // Add to the list of tests to be released by the parent. - t.parent.sub = append(t.parent.sub, t) - - // Report any races during execution of this test up to this point. - // - // We will assume that any races that occur between here and the point where - // we unblock are not caused by this subtest. That assumption usually holds, - // although it can be wrong if the test spawns a goroutine that races in the - // background while the rest of the test is blocked on the call to Parallel. - // If that happens, we will misattribute the background race to some other - // test, or to no test at all — but that false-negative is so unlikely that it - // is not worth adding race-report noise for the common case where the test is - // completely suspended during the call to Parallel. - t.checkRaces() - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name) - } - running.Delete(t.name) - - t.signal <- true // Release calling test. - <-t.parent.barrier // Wait for the parent test to complete. - t.tstate.waitParallel() - parallelStart.Add(1) - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== CONT %s\n", t.name) - } - running.Store(t.name, highPrecisionTimeNow()) - t.start = highPrecisionTimeNow() - - // Reset the local race counter to ignore any races that happened while this - // goroutine was blocked, such as in the parent test or in other parallel - // subtests. - // - // (Note that we don't call parent.checkRaces here: - // if other parallel subtests have already introduced races, we want to - // let them report those races instead of attributing them to the parent.) - t.lastRaceErrors.Store(int64(race.Errors())) -} - -func (t *T) checkParallel() { - // Non-parallel subtests that have parallel ancestors may still - // run in parallel with other tests: they are only non-parallel - // with respect to the other subtests of the same parent. - // Since calls like SetEnv or Chdir affects the whole process, we need - // to deny those if the current test or any parent is parallel. - for c := &t.common; c != nil; c = c.parent { - if c.isParallel { - panic(parallelConflict) - } - } - - t.denyParallel = true -} - -// Setenv calls os.Setenv(key, value) and uses Cleanup to -// restore the environment variable to its original value -// after the test. -// -// Because Setenv affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (t *T) Setenv(key, value string) { - t.checkParallel() - t.common.Setenv(key, value) -} - -// Chdir calls [os.Chdir] and uses Cleanup to restore the current -// working directory to its original value after the test. On Unix, it -// also sets PWD environment variable for the duration of the test. -// -// Because Chdir affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (t *T) Chdir(dir string) { - t.checkParallel() - t.common.Chdir(dir) -} - -// InternalTest is an internal type but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -type InternalTest struct { - Name string - F func(*T) -} - -var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit") - -func tRunner(t *T, fn func(t *T)) { - t.runner = callerName(0) - - // When this goroutine is done, either because fn(t) - // returned normally or because a test failure triggered - // a call to runtime.Goexit, record the duration and send - // a signal saying that the test is done. - defer func() { - t.checkRaces() - - // TODO(#61034): This is the wrong place for this check. - if t.Failed() { - numFailed.Add(1) - } - - // Check if the test panicked or Goexited inappropriately. - // - // If this happens in a normal test, print output but continue panicking. - // tRunner is called in its own goroutine, so this terminates the process. - // - // If this happens while fuzzing, recover from the panic and treat it like a - // normal failure. It's important that the process keeps running in order to - // find short inputs that cause panics. - err := recover() - signal := true - - t.mu.RLock() - finished := t.finished - t.mu.RUnlock() - if !finished && err == nil { - err = errNilPanicOrGoexit - for p := t.parent; p != nil; p = p.parent { - p.mu.RLock() - finished = p.finished - p.mu.RUnlock() - if finished { - if !t.isParallel { - t.Errorf("%v: subtest may have called FailNow on a parent test", err) - err = nil - } - signal = false - break - } - } - } - - if err != nil && t.tstate.isFuzzing { - prefix := "panic: " - if err == errNilPanicOrGoexit { - prefix = "" - } - t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack())) - t.mu.Lock() - t.finished = true - t.mu.Unlock() - err = nil - } - - // Use a deferred call to ensure that we report that the test is - // complete even if a cleanup function calls t.FailNow. See issue 41355. - didPanic := false - defer func() { - // Only report that the test is complete if it doesn't panic, - // as otherwise the test binary can exit before the panic is - // reported to the user. See issue 41479. - if didPanic { - return - } - if err != nil { - panic(err) - } - running.Delete(t.name) - if t.isParallel { - parallelStop.Add(1) - } - t.signal <- signal - }() - - doPanic := func(err any) { - t.Fail() - if r := t.runCleanup(recoverAndReturnPanic); r != nil { - t.Logf("cleanup panicked with %v", r) - } - // Flush the output log up to the root before dying. - // Skip this if this *T is a synctest bubble, because we're not a subtest. - for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent { - root.mu.Lock() - root.duration += highPrecisionTimeSince(root.start) - d := root.duration - root.mu.Unlock() - // Output buffered logs. - root.flushPartial() - root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) - if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil { - fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r) - } - } - didPanic = true - panic(err) - } - if err != nil { - doPanic(err) - } - - t.duration += highPrecisionTimeSince(t.start) - - if len(t.sub) > 0 { - // Run parallel subtests. - - // Decrease the running count for this test and mark it as no longer running. - t.tstate.release() - running.Delete(t.name) - - // Release the parallel subtests. - close(t.barrier) - // Wait for subtests to complete. - for _, sub := range t.sub { - <-sub.signal - } - - // Run any cleanup callbacks, marking the test as running - // in case the cleanup hangs. - cleanupStart := highPrecisionTimeNow() - running.Store(t.name, cleanupStart) - err := t.runCleanup(recoverAndReturnPanic) - t.duration += highPrecisionTimeSince(cleanupStart) - if err != nil { - doPanic(err) - } - t.checkRaces() - if !t.isParallel { - // Reacquire the count for sequential tests. See comment in Run. - t.tstate.waitParallel() - } - } else if t.isParallel { - // Only release the count for this test if it was run as a parallel - // test. See comment in Run method. - t.tstate.release() - } - // Output buffered logs. - for root := &t.common; root.parent != nil; root = root.parent { - root.flushPartial() - } - t.report() // Report after all subtests have finished. - - // Do not lock t.done to allow race detector to detect race in case - // the user does not appropriately synchronize a goroutine. - t.done = true - if t.parent != nil && !t.hasSub.Load() { - t.setRan() - } - }() - defer func() { - if len(t.sub) == 0 { - t.runCleanup(normalPanic) - } - }() - - t.start = highPrecisionTimeNow() - t.resetRaces() - fn(t) - - // code beyond here will not be executed when FailNow is invoked - t.mu.Lock() - t.finished = true - t.mu.Unlock() -} - -// Run runs f as a subtest of t called name. It runs f in a separate goroutine -// and blocks until f returns or calls t.Parallel to become a parallel test. -// Run reports whether f succeeded (or at least did not fail before calling t.Parallel). -// -// Run may be called simultaneously from multiple goroutines, but all such calls -// must return before the outer test function for t returns. -func (t *T) Run(name string, f func(t *T)) bool { - if t.isSynctest { - panic("testing: t.Run called inside synctest bubble") - } - if t.cleanupStarted.Load() { - panic("testing: t.Run called during t.Cleanup") - } - - t.hasSub.Store(true) - testName, ok, _ := t.tstate.match.fullName(&t.common, name) - if !ok || shouldFailFast() { - return true - } - // Record the stack trace at the point of this call so that if the subtest - // function - which runs in a separate stack - is marked as a helper, we can - // continue walking the stack into the parent test. - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - - // There's no reason to inherit this context from parent. The user's code can't observe - // the difference between the background context and the one from the parent test. - ctx, cancelCtx := context.WithCancel(context.Background()) - t = &T{ - common: common{ - barrier: make(chan bool), - signal: make(chan bool, 1), - name: testName, - parent: &t.common, - level: t.level + 1, - creator: pc[:n], - chatty: t.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: t.tstate, - } - t.w = indenter{&t.common} - t.setOutputWriter() - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) - } - running.Store(t.name, highPrecisionTimeNow()) - - // Instead of reducing the running count of this test before calling the - // tRunner and increasing it afterwards, we rely on tRunner keeping the - // count correct. This ensures that a sequence of sequential tests runs - // without being preempted, even when their parent is a parallel test. This - // may especially reduce surprises if *parallel == 1. - go tRunner(t, f) - - // The parent goroutine will block until the subtest either finishes or calls - // Parallel, but in general we don't know whether the parent goroutine is the - // top-level test function or some other goroutine it has spawned. - // To avoid confusing false-negatives, we leave the parent in the running map - // even though in the typical case it is blocked. - - if !<-t.signal { - // At this point, it is likely that FailNow was called on one of the - // parent tests by one of the subtests. Continue aborting up the chain. - runtime.Goexit() - } - - if t.chatty != nil && t.chatty.json { - t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name) - } - return !t.failed -} - -// testingSynctestTest runs f within a synctest bubble. -// It is called by synctest.Test, from within an already-created bubble. -// -//go:linkname testingSynctestTest_codspeed testing/synctest.testingSynctestTest_codspeed -func testingSynctestTest_codspeed(t *T, f func(*T)) (ok bool) { - if t.cleanupStarted.Load() { - panic("testing: synctest.Run called during t.Cleanup") - } - - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - - ctx, cancelCtx := context.WithCancel(context.Background()) - t2 := &T{ - common: common{ - barrier: make(chan bool), - signal: make(chan bool, 1), - name: t.name, - parent: &t.common, - level: t.level + 1, - creator: pc[:n], - chatty: t.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - isSynctest: true, - }, - tstate: t.tstate, - } - - go tRunner(t2, f) - if !<-t2.signal { - // At this point, it is likely that FailNow was called on one of the - // parent tests by one of the subtests. Continue aborting up the chain. - runtime.Goexit() - } - return !t2.failed -} - -// Deadline reports the time at which the test binary will have -// exceeded the timeout specified by the -timeout flag. -// -// The ok result is false if the -timeout flag indicates “no timeout” (0). -func (t *T) Deadline() (deadline time.Time, ok bool) { - if t.isSynctest { - // There's no point in returning a real-clock deadline to - // a test using a fake clock. We could return "no timeout", - // but panicking makes it easier for users to catch the error. - panic("testing: t.Deadline called inside synctest bubble") - } - deadline = t.tstate.deadline - return deadline, !deadline.IsZero() -} - -// testState holds all fields that are common to all tests. This includes -// synchronization primitives to run at most *parallel tests. -type testState struct { - match *matcher - deadline time.Time - - // isFuzzing is true in the state used when generating random inputs - // for fuzz targets. isFuzzing is false when running normal tests and - // when running fuzz tests as unit tests (without -fuzz or when -fuzz - // does not match). - isFuzzing bool - - mu sync.Mutex - - // Channel used to signal tests that are ready to be run in parallel. - startParallel chan bool - - // running is the number of tests currently running in parallel. - // This does not include tests that are waiting for subtests to complete. - running int - - // numWaiting is the number tests waiting to be run in parallel. - numWaiting int - - // maxParallel is a copy of the parallel flag. - maxParallel int -} - -func newTestState(maxParallel int, m *matcher) *testState { - return &testState{ - match: m, - startParallel: make(chan bool), - maxParallel: maxParallel, - running: 1, // Set the count to 1 for the main (sequential) test. - } -} - -func (s *testState) waitParallel() { - s.mu.Lock() - if s.running < s.maxParallel { - s.running++ - s.mu.Unlock() - return - } - s.numWaiting++ - s.mu.Unlock() - <-s.startParallel -} - -func (s *testState) release() { - s.mu.Lock() - if s.numWaiting == 0 { - s.running-- - s.mu.Unlock() - return - } - s.numWaiting-- - s.mu.Unlock() - s.startParallel <- true // Pick a waiting test to be run. -} - -// No one should be using func Main anymore. -// See the doc comment on func Main and use MainStart instead. -var errMain = errors.New("testing: unexpected use of func Main") - -type matchStringOnly func(pat, str string) (bool, error) - -func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) } -func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain } -func (f matchStringOnly) StopCPUProfile() {} -func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain } -func (f matchStringOnly) ImportPath() string { return "" } -func (f matchStringOnly) StartTestLog(io.Writer) {} -func (f matchStringOnly) StopTestLog() error { return errMain } -func (f matchStringOnly) SetPanicOnExit0(bool) {} -func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error { - return errMain -} -func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain } -func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) { - return nil, errMain -} -func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil } -func (f matchStringOnly) ResetCoverage() {} -func (f matchStringOnly) SnapshotCoverage() {} - -func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) { - return -} - -// Main is an internal function, part of the implementation of the "go test" command. -// It was exported because it is cross-package and predates "internal" packages. -// It is no longer used by "go test" but preserved, as much as possible, for other -// systems that simulate "go test" using Main, but Main sometimes cannot be updated as -// new functionality is added to the testing package. -// Systems simulating "go test" should be updated to use [MainStart]. -func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) { - os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run()) -} - -// M is a type passed to a TestMain function to run the actual tests. -type M struct { - deps testDeps - tests []InternalTest - benchmarks []InternalBenchmark - fuzzTargets []InternalFuzzTarget - examples []InternalExample - - timer *time.Timer - afterOnce sync.Once - - numRun int - - // value to pass to os.Exit, the outer test func main - // harness calls os.Exit with this code. See #34129. - exitCode int -} - -// testDeps is an internal interface of functionality that is -// passed into this package by a test's generated main package. -// The canonical implementation of this interface is -// testing/internal/testdeps's TestDeps. -type testDeps interface { - ImportPath() string - MatchString(pat, str string) (bool, error) - SetPanicOnExit0(bool) - StartCPUProfile(io.Writer) error - StopCPUProfile() - StartTestLog(io.Writer) - StopTestLog() error - WriteProfileTo(string, io.Writer, int) error - CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error - RunFuzzWorker(func(corpusEntry) error) error - ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) - CheckCorpus([]any, []reflect.Type) error - ResetCoverage() - SnapshotCoverage() - InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) -} - -// MainStart is meant for use by tests generated by 'go test'. -// It is not meant to be called directly and is not subject to the Go 1 compatibility document. -// It may change signature from release to release. -func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { - registerCover(deps.InitRuntimeCoverage()) - Init() - return &M{ - deps: deps, - tests: tests, - benchmarks: benchmarks, - fuzzTargets: fuzzTargets, - examples: examples, - } -} - -var ( - testingTesting bool - realStderr *os.File -) - -// Run runs the tests. It returns an exit code to pass to os.Exit. -// The exit code is zero when all tests pass, and non-zero for any kind -// of failure. For machine readable test results, parse the output of -// 'go test -json'. -func (m *M) Run() (code int) { - defer func() { - code = m.exitCode - }() - - // Count the number of calls to m.Run. - // We only ever expected 1, but we didn't enforce that, - // and now there are tests in the wild that call m.Run multiple times. - // Sigh. go.dev/issue/23129. - m.numRun++ - - // TestMain may have already called flag.Parse. - if !flag.Parsed() { - flag.Parse() - } - - if chatty.json { - // With -v=json, stdout and stderr are pointing to the same pipe, - // which is leading into test2json. In general, operating systems - // do a good job of ensuring that writes to the same pipe through - // different file descriptors are delivered whole, so that writing - // AAA to stdout and BBB to stderr simultaneously produces - // AAABBB or BBBAAA on the pipe, not something like AABBBA. - // However, the exception to this is when the pipe fills: in that - // case, Go's use of non-blocking I/O means that writing AAA - // or BBB might be split across multiple system calls, making it - // entirely possible to get output like AABBBA. The same problem - // happens inside the operating system kernel if we switch to - // blocking I/O on the pipe. This interleaved output can do things - // like print unrelated messages in the middle of a TestFoo line, - // which confuses test2json. Setting os.Stderr = os.Stdout will make - // them share a single pfd, which will hold a lock for each program - // write, preventing any interleaving. - // - // It might be nice to set Stderr = Stdout always, or perhaps if - // we can tell they are the same file, but for now -v=json is - // a very clear signal. Making the two files the same may cause - // surprises if programs close os.Stdout but expect to be able - // to continue to write to os.Stderr, but it's hard to see why a - // test would think it could take over global state that way. - // - // This fix only helps programs where the output is coming directly - // from Go code. It does not help programs in which a subprocess is - // writing to stderr or stdout at the same time that a Go test is writing output. - // It also does not help when the output is coming from the runtime, - // such as when using the print/println functions, since that code writes - // directly to fd 2 without any locking. - // We keep realStderr around to prevent fd 2 from being closed. - // - // See go.dev/issue/33419. - realStderr = os.Stderr - os.Stderr = os.Stdout - } - - if *parallel < 1 { - fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer") - flag.Usage() - m.exitCode = 2 - return - } - if *matchFuzz != "" && *fuzzCacheDir == "" { - fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set") - flag.Usage() - m.exitCode = 2 - return - } - - if *matchList != "" { - listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples) - m.exitCode = 0 - return - } - - if *shuffle != "off" { - var n int64 - var err error - if *shuffle == "on" { - n = time.Now().UnixNano() - } else { - n, err = strconv.ParseInt(*shuffle, 10, 64) - if err != nil { - fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err) - m.exitCode = 2 - return - } - } - fmt.Println("-test.shuffle", n) - rng := rand.New(rand.NewSource(n)) - rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] }) - rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] }) - } - - parseCpuList() - - m.before() - defer m.after() - - // Run tests, examples, and benchmarks unless this is a fuzz worker process. - // Workers start after this is done by their parent process, and they should - // not repeat this work. - if !*isFuzzWorker { - deadline := m.startAlarm() - haveExamples = len(m.examples) > 0 - testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline) - fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline) - exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples) - m.stopAlarm() - if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" { - fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") - if testingTesting && *match != "^$" { - // If this happens during testing of package testing it could be that - // package testing's own logic for when to run a test is broken, - // in which case every test will run nothing and succeed, - // with no obvious way to detect this problem (since no tests are running). - // So make 'no tests to run' a hard failure when testing package testing itself. - fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n") - testOk = false - } - } - anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) - if !anyFailed && race.Errors() > 0 { - fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n") - anyFailed = true - } - if anyFailed { - fmt.Print(chatty.prefix(), "FAIL\n") - m.exitCode = 1 - return - } - } - - fuzzingOk := runFuzzing(m.deps, m.fuzzTargets) - if !fuzzingOk { - fmt.Print(chatty.prefix(), "FAIL\n") - if *isFuzzWorker { - m.exitCode = fuzzWorkerExitCode - } else { - m.exitCode = 1 - } - return - } - - m.exitCode = 0 - if !*isFuzzWorker { - fmt.Print(chatty.prefix(), "PASS\n") - } - return -} - -func (t *T) report() { - if t.parent == nil { - return - } - if t.isSynctest { - return // t.parent will handle reporting - } - dstr := fmtDuration(t.duration) - format := "--- %s: %s (%s)\n" - if t.Failed() { - t.flushToParent(t.name, format, "FAIL", t.name, dstr) - } else if t.chatty != nil { - if t.Skipped() { - t.flushToParent(t.name, format, "SKIP", t.name, dstr) - } else { - t.flushToParent(t.name, format, "PASS", t.name, dstr) - } - } -} - -func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) { - if _, err := matchString(*matchList, "non-empty"); err != nil { - fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err) - os.Exit(1) - } - - for _, test := range tests { - if ok, _ := matchString(*matchList, test.Name); ok { - fmt.Println(test.Name) - } - } - for _, bench := range benchmarks { - if ok, _ := matchString(*matchList, bench.Name); ok { - fmt.Println(bench.Name) - } - } - for _, fuzzTarget := range fuzzTargets { - if ok, _ := matchString(*matchList, fuzzTarget.Name); ok { - fmt.Println(fuzzTarget.Name) - } - } - for _, example := range examples { - if ok, _ := matchString(*matchList, example.Name); ok { - fmt.Println(example.Name) - } - } -} - -// RunTests is an internal function but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) { - var deadline time.Time - if *timeout > 0 { - deadline = time.Now().Add(*timeout) - } - ran, ok := runTests(matchString, tests, deadline) - if !ran && !haveExamples { - fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") - } - return ok -} - -func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) { - ok = true - for _, procs := range cpuList { - runtime.GOMAXPROCS(procs) - for i := uint(0); i < *count; i++ { - if shouldFailFast() { - break - } - if i > 0 && !ran { - // There were no tests to run on the first - // iteration. This won't change, so no reason - // to keep trying. - break - } - ctx, cancelCtx := context.WithCancel(context.Background()) - tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip)) - tstate.deadline = deadline - t := &T{ - common: common{ - signal: make(chan bool, 1), - barrier: make(chan bool), - w: os.Stdout, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: tstate, - } - if Verbose() { - t.chatty = newChattyPrinter(t.w) - } - tRunner(t, func(t *T) { - for _, test := range tests { - t.Run(test.Name, test.F) - } - }) - select { - case <-t.signal: - default: - panic("internal error: tRunner exited without sending on t.signal") - } - ok = ok && !t.Failed() - ran = ran || t.ran - } - } - return ran, ok -} - -// before runs before all testing. -func (m *M) before() { - if *memProfileRate > 0 { - runtime.MemProfileRate = *memProfileRate - } - if *cpuProfile != "" { - f, err := os.Create(toOutputDir(*cpuProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - return - } - if err := m.deps.StartCPUProfile(f); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err) - f.Close() - return - } - // Could save f so after can call f.Close; not worth the effort. - } - if *traceFile != "" { - f, err := os.Create(toOutputDir(*traceFile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - return - } - if err := trace.Start(f); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err) - f.Close() - return - } - // Could save f so after can call f.Close; not worth the effort. - } - if *blockProfile != "" && *blockProfileRate >= 0 { - runtime.SetBlockProfileRate(*blockProfileRate) - } - if *mutexProfile != "" && *mutexProfileFraction >= 0 { - runtime.SetMutexProfileFraction(*mutexProfileFraction) - } - if *coverProfile != "" && CoverMode() == "" { - fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n") - os.Exit(2) - } - if *gocoverdir != "" && CoverMode() == "" { - fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n") - os.Exit(2) - } - if *testlog != "" { - // Note: Not using toOutputDir. - // This file is for use by cmd/go, not users. - var f *os.File - var err error - if m.numRun == 1 { - f, err = os.Create(*testlog) - } else { - f, err = os.OpenFile(*testlog, os.O_WRONLY, 0) - if err == nil { - f.Seek(0, io.SeekEnd) - } - } - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - m.deps.StartTestLog(f) - testlogFile = f - } - if *panicOnExit0 { - m.deps.SetPanicOnExit0(true) - } -} - -// after runs after all testing. -func (m *M) after() { - m.afterOnce.Do(func() { - m.writeProfiles() - }) - - // Restore PanicOnExit0 after every run, because we set it to true before - // every run. Otherwise, if m.Run is called multiple times the behavior of - // os.Exit(0) will not be restored after the second run. - if *panicOnExit0 { - m.deps.SetPanicOnExit0(false) - } -} - -func (m *M) writeProfiles() { - if *testlog != "" { - if err := m.deps.StopTestLog(); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err) - os.Exit(2) - } - if err := testlogFile.Close(); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err) - os.Exit(2) - } - } - if *cpuProfile != "" { - m.deps.StopCPUProfile() // flushes profile to disk - } - if *traceFile != "" { - trace.Stop() // flushes trace to disk - } - if *memProfile != "" { - f, err := os.Create(toOutputDir(*memProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - runtime.GC() // materialize all statistics - if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err) - os.Exit(2) - } - f.Close() - } - if *blockProfile != "" && *blockProfileRate >= 0 { - f, err := os.Create(toOutputDir(*blockProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - if err = m.deps.WriteProfileTo("block", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err) - os.Exit(2) - } - f.Close() - } - if *mutexProfile != "" && *mutexProfileFraction >= 0 { - f, err := os.Create(toOutputDir(*mutexProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err) - os.Exit(2) - } - f.Close() - } - if CoverMode() != "" { - coverReport() - } -} - -// toOutputDir returns the file name relocated, if required, to outputDir. -// Simple implementation to avoid pulling in path/filepath. -func toOutputDir(path string) string { - if *outputDir == "" || path == "" { - return path - } - // On Windows, it's clumsy, but we can be almost always correct - // by just looking for a drive letter and a colon. - // Absolute paths always have a drive letter (ignoring UNC). - // Problem: if path == "C:A" and outputdir == "C:\Go" it's unclear - // what to do, but even then path/filepath doesn't help. - // TODO: Worth doing better? Probably not, because we're here only - // under the management of go test. - if runtime.GOOS == "windows" && len(path) >= 2 { - letter, colon := path[0], path[1] - if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' { - // If path starts with a drive letter we're stuck with it regardless. - return path - } - } - if os.IsPathSeparator(path[0]) { - return path - } - return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path) -} - -// startAlarm starts an alarm if requested. -func (m *M) startAlarm() time.Time { - if *timeout <= 0 { - return time.Time{} - } - - deadline := time.Now().Add(*timeout) - m.timer = time.AfterFunc(*timeout, func() { - m.after() - debug.SetTraceback("all") - extra := "" - - if list := runningList(); len(list) > 0 { - var b strings.Builder - b.WriteString("\nrunning tests:") - for _, name := range list { - b.WriteString("\n\t") - b.WriteString(name) - } - extra = b.String() - } - panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra)) - }) - return deadline -} - -// runningList returns the list of running tests. -func runningList() []string { - var list []string - running.Range(func(k, v any) bool { - list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second))) - return true - }) - slices.Sort(list) - return list -} - -// stopAlarm turns off the alarm. -func (m *M) stopAlarm() { - if *timeout > 0 { - m.timer.Stop() - } -} - -func parseCpuList() { - for val := range strings.SplitSeq(*cpuListStr, ",") { - val = strings.TrimSpace(val) - if val == "" { - continue - } - cpu, err := strconv.Atoi(val) - if err != nil || cpu <= 0 { - fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val) - os.Exit(1) - } - cpuList = append(cpuList, cpu) - } - if cpuList == nil { - cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) - } -} - -func shouldFailFast() bool { - return *failFast && numFailed.Load() > 0 -} diff --git a/testing/testing/testing.go.orig b/testing/testing/testing.go.orig deleted file mode 100644 index 067e3265..00000000 --- a/testing/testing/testing.go.orig +++ /dev/null @@ -1,2725 +0,0 @@ -// Copyright 2009 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 provides support for automated testing of Go packages. -// It is intended to be used in concert with the "go test" command, which automates -// execution of any function of the form -// -// func TestXxx(*testing.T) -// -// where Xxx does not start with a lowercase letter. The function name -// serves to identify the test routine. -// -// Within these functions, use [T.Error], [T.Fail] or related methods to signal failure. -// -// To write a new test suite, create a file that -// contains the TestXxx functions as described here, -// and give that file a name ending in "_test.go". -// The file will be excluded from regular -// package builds but will be included when the "go test" command is run. -// -// The test file can be in the same package as the one being tested, -// or in a corresponding package with the suffix "_test". -// -// If the test file is in the same package, it may refer to unexported -// identifiers within the package, as in this example: -// -// package abs -// -// import "testing" -// -// func TestAbs(t *testing.T) { -// got := Abs(-1) -// if got != 1 { -// t.Errorf("Abs(-1) = %d; want 1", got) -// } -// } -// -// If the file is in a separate "_test" package, the package being tested -// must be imported explicitly and only its exported identifiers may be used. -// This is known as "black box" testing. -// -// package abs_test -// -// import ( -// "testing" -// -// "path_to_pkg/abs" -// ) -// -// func TestAbs(t *testing.T) { -// got := abs.Abs(-1) -// if got != 1 { -// t.Errorf("Abs(-1) = %d; want 1", got) -// } -// } -// -// For more detail, run [go help test] and [go help testflag]. -// -// # Benchmarks -// -// Functions of the form -// -// func BenchmarkXxx(*testing.B) -// -// are considered benchmarks, and are executed by the "go test" command when -// its -bench flag is provided. Benchmarks are run sequentially. -// -// For a description of the testing flags, see [go help testflag]. -// -// A sample benchmark function looks like this: -// -// func BenchmarkRandInt(b *testing.B) { -// for b.Loop() { -// rand.Int() -// } -// } -// -// The output -// -// BenchmarkRandInt-8 68453040 17.8 ns/op -// -// means that the body of the loop ran 68453040 times at a speed of 17.8 ns per loop. -// -// Only the body of the loop is timed, so benchmarks may do expensive -// setup before calling b.Loop, which will not be counted toward the -// benchmark measurement: -// -// func BenchmarkBigLen(b *testing.B) { -// big := NewBig() -// for b.Loop() { -// big.Len() -// } -// } -// -// If a benchmark needs to test performance in a parallel setting, it may use -// the RunParallel helper function; such benchmarks are intended to be used with -// the go test -cpu flag: -// -// func BenchmarkTemplateParallel(b *testing.B) { -// templ := template.Must(template.New("test").Parse("Hello, {{.}}!")) -// b.RunParallel(func(pb *testing.PB) { -// var buf bytes.Buffer -// for pb.Next() { -// buf.Reset() -// templ.Execute(&buf, "World") -// } -// }) -// } -// -// A detailed specification of the benchmark results format is given -// in https://go.dev/design/14313-benchmark-format. -// -// There are standard tools for working with benchmark results at -// [golang.org/x/perf/cmd]. -// In particular, [golang.org/x/perf/cmd/benchstat] performs -// statistically robust A/B comparisons. -// -// # b.N-style benchmarks -// -// Prior to the introduction of [B.Loop], benchmarks were written in a -// different style using B.N. For example: -// -// func BenchmarkRandInt(b *testing.B) { -// for range b.N { -// rand.Int() -// } -// } -// -// In this style of benchmark, the benchmark function must run -// the target code b.N times. The benchmark function is called -// multiple times with b.N adjusted until the benchmark function -// lasts long enough to be timed reliably. This also means any setup -// done before the loop may be run several times. -// -// If a benchmark needs some expensive setup before running, the timer -// should be explicitly reset: -// -// func BenchmarkBigLen(b *testing.B) { -// big := NewBig() -// b.ResetTimer() -// for range b.N { -// big.Len() -// } -// } -// -// New benchmarks should prefer using [B.Loop], which is more robust -// and more efficient. -// -// # Examples -// -// The package also runs and verifies example code. Example functions may -// include a concluding line comment that begins with "Output:" and is compared with -// the standard output of the function when the tests are run. (The comparison -// ignores leading and trailing space.) These are examples of an example: -// -// func ExampleHello() { -// fmt.Println("hello") -// // Output: hello -// } -// -// func ExampleSalutations() { -// fmt.Println("hello, and") -// fmt.Println("goodbye") -// // Output: -// // hello, and -// // goodbye -// } -// -// The comment prefix "Unordered output:" is like "Output:", but matches any -// line order: -// -// func ExamplePerm() { -// for _, value := range Perm(5) { -// fmt.Println(value) -// } -// // Unordered output: 4 -// // 2 -// // 1 -// // 3 -// // 0 -// } -// -// Example functions without output comments are compiled but not executed. -// -// The naming convention to declare examples for the package, a function F, a type T and -// method M on type T are: -// -// func Example() { ... } -// func ExampleF() { ... } -// func ExampleT() { ... } -// func ExampleT_M() { ... } -// -// Multiple example functions for a package/type/function/method may be provided by -// appending a distinct suffix to the name. The suffix must start with a -// lower-case letter. -// -// func Example_suffix() { ... } -// func ExampleF_suffix() { ... } -// func ExampleT_suffix() { ... } -// func ExampleT_M_suffix() { ... } -// -// The entire test file is presented as the example when it contains a single -// example function, at least one other function, type, variable, or constant -// declaration, and no test or benchmark functions. -// -// # Fuzzing -// -// 'go test' and the testing package support fuzzing, a testing technique where -// a function is called with randomly generated inputs to find bugs not -// anticipated by unit tests. -// -// Functions of the form -// -// func FuzzXxx(*testing.F) -// -// are considered fuzz tests. -// -// For example: -// -// func FuzzHex(f *testing.F) { -// for _, seed := range [][]byte{{}, {0}, {9}, {0xa}, {0xf}, {1, 2, 3, 4}} { -// f.Add(seed) -// } -// f.Fuzz(func(t *testing.T, in []byte) { -// enc := hex.EncodeToString(in) -// out, err := hex.DecodeString(enc) -// if err != nil { -// t.Fatalf("%v: decode: %v", in, err) -// } -// if !bytes.Equal(in, out) { -// t.Fatalf("%v: not equal after round trip: %v", in, out) -// } -// }) -// } -// -// A fuzz test maintains a seed corpus, or a set of inputs which are run by -// default, and can seed input generation. Seed inputs may be registered by -// calling [F.Add] or by storing files in the directory testdata/fuzz/ -// (where is the name of the fuzz test) within the package containing -// the fuzz test. Seed inputs are optional, but the fuzzing engine may find -// bugs more efficiently when provided with a set of small seed inputs with good -// code coverage. These seed inputs can also serve as regression tests for bugs -// identified through fuzzing. -// -// The function passed to [F.Fuzz] within the fuzz test is considered the fuzz -// target. A fuzz target must accept a [*T] parameter, followed by one or more -// parameters for random inputs. The types of arguments passed to [F.Add] must -// be identical to the types of these parameters. The fuzz target may signal -// that it's found a problem the same way tests do: by calling [T.Fail] (or any -// method that calls it like [T.Error] or [T.Fatal]) or by panicking. -// -// When fuzzing is enabled (by setting the -fuzz flag to a regular expression -// that matches a specific fuzz test), the fuzz target is called with arguments -// generated by repeatedly making random changes to the seed inputs. On -// supported platforms, 'go test' compiles the test executable with fuzzing -// coverage instrumentation. The fuzzing engine uses that instrumentation to -// find and cache inputs that expand coverage, increasing the likelihood of -// finding bugs. If the fuzz target fails for a given input, the fuzzing engine -// writes the inputs that caused the failure to a file in the directory -// testdata/fuzz/ within the package directory. This file later serves as -// a seed input. If the file can't be written at that location (for example, -// because the directory is read-only), the fuzzing engine writes the file to -// the fuzz cache directory within the build cache instead. -// -// When fuzzing is disabled, the fuzz target is called with the seed inputs -// registered with [F.Add] and seed inputs from testdata/fuzz/. In this -// mode, the fuzz test acts much like a regular test, with subtests started -// with [F.Fuzz] instead of [T.Run]. -// -// See https://go.dev/doc/fuzz for documentation about fuzzing. -// -// # Skipping -// -// Tests or benchmarks may be skipped at run time with a call to -// [T.Skip] or [B.Skip]: -// -// func TestTimeConsuming(t *testing.T) { -// if testing.Short() { -// t.Skip("skipping test in short mode.") -// } -// ... -// } -// -// The [T.Skip] method can be used in a fuzz target if the input is invalid, -// but should not be considered a failing input. For example: -// -// func FuzzJSONMarshaling(f *testing.F) { -// f.Fuzz(func(t *testing.T, b []byte) { -// var v interface{} -// if err := json.Unmarshal(b, &v); err != nil { -// t.Skip() -// } -// if _, err := json.Marshal(v); err != nil { -// t.Errorf("Marshal: %v", err) -// } -// }) -// } -// -// # Subtests and Sub-benchmarks -// -// The [T.Run] and [B.Run] methods allow defining subtests and sub-benchmarks, -// without having to define separate functions for each. This enables uses -// like table-driven benchmarks and creating hierarchical tests. -// It also provides a way to share common setup and tear-down code: -// -// func TestFoo(t *testing.T) { -// // -// t.Run("A=1", func(t *testing.T) { ... }) -// t.Run("A=2", func(t *testing.T) { ... }) -// t.Run("B=1", func(t *testing.T) { ... }) -// // -// } -// -// Each subtest and sub-benchmark has a unique name: the combination of the name -// of the top-level test and the sequence of names passed to Run, separated by -// slashes, with an optional trailing sequence number for disambiguation. -// -// The argument to the -run, -bench, and -fuzz command-line flags is an unanchored regular -// expression that matches the test's name. For tests with multiple slash-separated -// elements, such as subtests, the argument is itself slash-separated, with -// expressions matching each name element in turn. Because it is unanchored, an -// empty expression matches any string. -// For example, using "matching" to mean "whose name contains": -// -// go test -run '' # Run all tests. -// go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar". -// go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=". -// go test -run /A=1 # For all top-level tests, run subtests matching "A=1". -// go test -fuzz FuzzFoo # Fuzz the target matching "FuzzFoo" -// -// The -run argument can also be used to run a specific value in the seed -// corpus, for debugging. For example: -// -// go test -run=FuzzFoo/9ddb952d9814 -// -// The -fuzz and -run flags can both be set, in order to fuzz a target but -// skip the execution of all other tests. -// -// Subtests can also be used to control parallelism. A parent test will only -// complete once all of its subtests complete. In this example, all tests are -// run in parallel with each other, and only with each other, regardless of -// other top-level tests that may be defined: -// -// func TestGroupedParallel(t *testing.T) { -// for _, tc := range tests { -// t.Run(tc.Name, func(t *testing.T) { -// t.Parallel() -// ... -// }) -// } -// } -// -// Run does not return until parallel subtests have completed, providing a way -// to clean up after a group of parallel tests: -// -// func TestTeardownParallel(t *testing.T) { -// // This Run will not return until the parallel tests finish. -// t.Run("group", func(t *testing.T) { -// t.Run("Test1", parallelTest1) -// t.Run("Test2", parallelTest2) -// t.Run("Test3", parallelTest3) -// }) -// // -// } -// -// # Main -// -// It is sometimes necessary for a test or benchmark program to do extra setup or teardown -// before or after it executes. It is also sometimes necessary to control -// which code runs on the main thread. To support these and other cases, -// if a test file contains a function: -// -// func TestMain(m *testing.M) -// -// then the generated test will call TestMain(m) instead of running the tests or benchmarks -// directly. TestMain runs in the main goroutine and can do whatever setup -// and teardown is necessary around a call to m.Run. m.Run will return an exit -// code that may be passed to [os.Exit]. If TestMain returns, the test wrapper -// will pass the result of m.Run to [os.Exit] itself. -// -// When TestMain is called, flag.Parse has not been run. If TestMain depends on -// command-line flags, including those of the testing package, it should call -// [flag.Parse] explicitly. Command line flags are always parsed by the time test -// or benchmark functions run. -// -// A simple implementation of TestMain is: -// -// func TestMain(m *testing.M) { -// // call flag.Parse() here if TestMain uses flags -// m.Run() -// } -// -// TestMain is a low-level primitive and should not be necessary for casual -// testing needs, where ordinary test functions suffice. -// -// [go help test]: https://pkg.go.dev/cmd/go#hdr-Test_packages -// [go help testflag]: https://pkg.go.dev/cmd/go#hdr-Testing_flags -package testing - -import ( - "bytes" - "context" - "errors" - "flag" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/race" - "io" - "math/rand" - "os" - "path/filepath" - "reflect" - "runtime" - "runtime/debug" - "runtime/trace" - "slices" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - "unicode" - "unicode/utf8" - _ "unsafe" // for linkname -) - -var initRan bool - -var ( - parallelStart atomic.Int64 // number of parallel tests started - parallelStop atomic.Int64 // number of parallel tests stopped -) - -// Init registers testing flags. These flags are automatically registered by -// the "go test" command before running test functions, so Init is only needed -// when calling functions such as Benchmark without using "go test". -// -// Init is not safe to call concurrently. It has no effect if it was already called. -func Init() { - if initRan { - return - } - initRan = true - // The short flag requests that tests run more quickly, but its functionality - // is provided by test writers themselves. The testing package is just its - // home. The all.bash installation script sets it to make installation more - // efficient, but by default the flag is off so a plain "go test" will do a - // full test of the package. - short = flag.Bool("test.short", false, "run smaller test suite to save time") - - // The failfast flag requests that test execution stop after the first test failure. - failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure") - - // The directory in which to create profile files and the like. When run from - // "go test", the binary always runs in the source directory for the package; - // this flag lets "go test" tell the binary to write the files in the directory where - // the "go test" command is run. - outputDir = flag.String("test.outputdir", "", "write profiles to `dir`") - // Report as tests are run; default is silent for success. - flag.Var(&chatty, "test.v", "verbose: print additional output") - count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times") - coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`") - gocoverdir = flag.String("test.gocoverdir", "", "write coverage intermediate files to this directory") - matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit") - match = flag.String("test.run", "", "run only tests and examples matching `regexp`") - skip = flag.String("test.skip", "", "do not list or run tests matching `regexp`") - memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`") - memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)") - cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`") - blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`") - blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)") - mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution") - mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()") - panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)") - traceFile = flag.String("test.trace", "", "write an execution trace to `file`") - timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)") - cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with") - parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel") - testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)") - shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks") - fullPath = flag.Bool("test.fullpath", false, "show full file names in error messages") - - initBenchmarkFlags() - initFuzzFlags() -} - -var ( - // Flags, registered during Init. - short *bool - failFast *bool - outputDir *string - chatty chattyFlag - count *uint - coverProfile *string - gocoverdir *string - matchList *string - match *string - skip *string - memProfile *string - memProfileRate *int - cpuProfile *string - blockProfile *string - blockProfileRate *int - mutexProfile *string - mutexProfileFraction *int - panicOnExit0 *bool - traceFile *string - timeout *time.Duration - cpuListStr *string - parallel *int - shuffle *string - testlog *string - fullPath *bool - - haveExamples bool // are there examples? - - cpuList []int - testlogFile *os.File - - numFailed atomic.Uint32 // number of test failures - - running sync.Map // map[string]time.Time of running, unpaused tests -) - -type chattyFlag struct { - on bool // -v is set in some form - json bool // -v=test2json is set, to make output better for test2json -} - -func (*chattyFlag) IsBoolFlag() bool { return true } - -func (f *chattyFlag) Set(arg string) error { - switch arg { - default: - return fmt.Errorf("invalid flag -test.v=%s", arg) - case "true", "test2json": - f.on = true - f.json = arg == "test2json" - case "false": - f.on = false - f.json = false - } - return nil -} - -func (f *chattyFlag) String() string { - if f.json { - return "test2json" - } - if f.on { - return "true" - } - return "false" -} - -func (f *chattyFlag) Get() any { - if f.json { - return "test2json" - } - return f.on -} - -const marker = byte(0x16) // ^V for framing - -func (f *chattyFlag) prefix() string { - if f.json { - return string(marker) - } - return "" -} - -type chattyPrinter struct { - w io.Writer - lastNameMu sync.Mutex // guards lastName - lastName string // last printed test name in chatty mode - json bool // -v=json output mode -} - -func newChattyPrinter(w io.Writer) *chattyPrinter { - return &chattyPrinter{w: w, json: chatty.json} -} - -// prefix is like chatty.prefix but using p.json instead of chatty.json. -// Using p.json allows tests to check the json behavior without modifying -// the global variable. For convenience, we allow p == nil and treat -// that as not in json mode (because it's not chatty at all). -func (p *chattyPrinter) prefix() string { - if p != nil && p.json { - return string(marker) - } - return "" -} - -// Updatef prints a message about the status of the named test to w. -// -// The formatted message must include the test name itself. -func (p *chattyPrinter) Updatef(testName, format string, args ...any) { - p.lastNameMu.Lock() - defer p.lastNameMu.Unlock() - - // Since the message already implies an association with a specific new test, - // we don't need to check what the old test name was or log an extra NAME line - // for it. (We're updating it anyway, and the current message already includes - // the test name.) - p.lastName = testName - fmt.Fprintf(p.w, p.prefix()+format, args...) -} - -// Printf prints a message, generated by the named test, that does not -// necessarily mention that tests's name itself. -func (p *chattyPrinter) Printf(testName, format string, args ...any) { - p.lastNameMu.Lock() - defer p.lastNameMu.Unlock() - - if p.lastName == "" { - p.lastName = testName - } else if p.lastName != testName { - fmt.Fprintf(p.w, "%s=== NAME %s\n", p.prefix(), testName) - p.lastName = testName - } - - fmt.Fprintf(p.w, format, args...) -} - -// The maximum number of stack frames to go through when skipping helper functions for -// the purpose of decorating log messages. -const maxStackLen = 50 - -// common holds the elements common between T and B and -// captures common methods such as Errorf. -type common struct { - mu sync.RWMutex // guards this group of fields - output []byte // Output generated by test or benchmark. - w io.Writer // For flushToParent. - o *outputWriter // Writes output. - ran bool // Test or benchmark (or one of its subtests) was executed. - failed bool // Test or benchmark has failed. - skipped bool // Test or benchmark has been skipped. - done bool // Test is finished and all subtests have completed. - helperPCs map[uintptr]struct{} // functions to be skipped when writing file/line info - helperNames map[string]struct{} // helperPCs converted to function names - cleanups []func() // optional functions to be called at the end of the test - cleanupName string // Name of the cleanup function. - cleanupPc []uintptr // The stack trace at the point where Cleanup was called. - finished bool // Test function has completed. - inFuzzFn bool // Whether the fuzz target, if this is one, is running. - isSynctest bool - - chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set. - bench bool // Whether the current test is a benchmark. - hasSub atomic.Bool // whether there are sub-benchmarks. - cleanupStarted atomic.Bool // Registered cleanup callbacks have started to execute - runner string // Function name of tRunner running the test. - isParallel bool // Whether the test is parallel. - - parent *common - level int // Nesting depth of test or benchmark. - creator []uintptr // If level > 0, the stack trace at the point where the parent called t.Run. - name string // Name of test or benchmark. - start highPrecisionTime // Time test or benchmark started - duration time.Duration - barrier chan bool // To signal parallel subtests they may start. Nil when T.Parallel is not present (B) or not usable (when fuzzing). - signal chan bool // To signal a test is done. - sub []*T // Queue of subtests to be run in parallel. - - lastRaceErrors atomic.Int64 // Max value of race.Errors seen during the test or its subtests. - raceErrorLogged atomic.Bool - - tempDirMu sync.Mutex - tempDir string - tempDirErr error - tempDirSeq int32 - - ctx context.Context - cancelCtx context.CancelFunc -} - -// Short reports whether the -test.short flag is set. -func Short() bool { - if short == nil { - panic("testing: Short called before Init") - } - // Catch code that calls this from TestMain without first calling flag.Parse. - if !flag.Parsed() { - panic("testing: Short called before Parse") - } - - return *short -} - -// testBinary is set by cmd/go to "1" if this is a binary built by "go test". -// The value is set to "1" by a -X option to cmd/link. We assume that -// because this is possible, the compiler will not optimize testBinary -// into a constant on the basis that it is an unexported package-scope -// variable that is never changed. If the compiler ever starts implementing -// such an optimization, we will need some technique to mark this variable -// as "changed by a cmd/link -X option". -var testBinary = "0" - -// Testing reports whether the current code is being run in a test. -// This will report true in programs created by "go test", -// false in programs created by "go build". -func Testing() bool { - return testBinary == "1" -} - -// CoverMode reports what the test coverage mode is set to. The -// values are "set", "count", or "atomic". The return value will be -// empty if test coverage is not enabled. -func CoverMode() string { - return cover.mode -} - -// Verbose reports whether the -test.v flag is set. -func Verbose() bool { - // Same as in Short. - if !flag.Parsed() { - panic("testing: Verbose called before Parse") - } - return chatty.on -} - -func (c *common) checkFuzzFn(name string) { - if c.inFuzzFn { - panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name)) - } -} - -// frameSkip searches, starting after skip frames, for the first caller frame -// in a function not marked as a helper and returns that frame. -// The search stops if it finds a tRunner function that -// was the entry point into the test and the test is not a subtest. -// This function must be called with c.mu held. -func (c *common) frameSkip(skip int) runtime.Frame { - // If the search continues into the parent test, we'll have to hold - // its mu temporarily. If we then return, we need to unlock it. - shouldUnlock := false - defer func() { - if shouldUnlock { - c.mu.Unlock() - } - }() - var pc [maxStackLen]uintptr - // Skip two extra frames to account for this function - // and runtime.Callers itself. - n := runtime.Callers(skip+2, pc[:]) - if n == 0 { - panic("testing: zero callers found") - } - frames := runtime.CallersFrames(pc[:n]) - var firstFrame, prevFrame, frame runtime.Frame - for more := true; more; prevFrame = frame { - frame, more = frames.Next() - if frame.Function == "runtime.gopanic" { - continue - } - if frame.Function == c.cleanupName { - frames = runtime.CallersFrames(c.cleanupPc) - continue - } - if firstFrame.PC == 0 { - firstFrame = frame - } - if frame.Function == c.runner { - // We've gone up all the way to the tRunner calling - // the test function (so the user must have - // called tb.Helper from inside that test function). - // If this is a top-level test, only skip up to the test function itself. - // If we're in a subtest, continue searching in the parent test, - // starting from the point of the call to Run which created this subtest. - if c.level > 1 { - frames = runtime.CallersFrames(c.creator) - parent := c.parent - // We're no longer looking at the current c after this point, - // so we should unlock its mu, unless it's the original receiver, - // in which case our caller doesn't expect us to do that. - if shouldUnlock { - c.mu.Unlock() - } - c = parent - // Remember to unlock c.mu when we no longer need it, either - // because we went up another nesting level, or because we - // returned. - shouldUnlock = true - c.mu.Lock() - continue - } - return prevFrame - } - // If more helper PCs have been added since we last did the conversion - if c.helperNames == nil { - c.helperNames = make(map[string]struct{}) - for pc := range c.helperPCs { - c.helperNames[pcToName(pc)] = struct{}{} - } - } - if _, ok := c.helperNames[frame.Function]; !ok { - // Found a frame that wasn't inside a helper function. - return frame - } - } - return firstFrame -} - -// flushToParent writes c.output to the parent after first writing the header -// with the given format and arguments. -func (c *common) flushToParent(testName, format string, args ...any) { - p := c.parent - p.mu.Lock() - defer p.mu.Unlock() - - c.mu.Lock() - defer c.mu.Unlock() - - if len(c.output) > 0 { - // Add the current c.output to the print, - // and then arrange for the print to replace c.output. - // (This displays the logged output after the --- FAIL line.) - format += "%s" - args = append(args[:len(args):len(args)], c.output) - c.output = c.output[:0] - } - - if c.chatty != nil && (p.w == c.chatty.w || c.chatty.json) { - // We're flushing to the actual output, so track that this output is - // associated with a specific test (and, specifically, that the next output - // is *not* associated with that test). - // - // Moreover, if c.output is non-empty it is important that this write be - // atomic with respect to the output of other tests, so that we don't end up - // with confusing '=== NAME' lines in the middle of our '--- PASS' block. - // Neither humans nor cmd/test2json can parse those easily. - // (See https://go.dev/issue/40771.) - // - // If test2json is used, we never flush to parent tests, - // so that the json stream shows subtests as they finish. - // (See https://go.dev/issue/29811.) - c.chatty.Updatef(testName, format, args...) - } else { - // We're flushing to the output buffer of the parent test, which will - // itself follow a test-name header when it is finally flushed to stdout. - fmt.Fprintf(p.w, c.chatty.prefix()+format, args...) - } -} - -type indenter struct { - c *common -} - -const indent = " " - -func (w indenter) Write(b []byte) (n int, err error) { - n = len(b) - for len(b) > 0 { - end := bytes.IndexByte(b, '\n') - if end == -1 { - end = len(b) - } else { - end++ - } - // An indent of 4 spaces will neatly align the dashes with the status - // indicator of the parent. - line := b[:end] - if line[0] == marker { - w.c.output = append(w.c.output, marker) - line = line[1:] - } - w.c.output = append(w.c.output, indent...) - w.c.output = append(w.c.output, line...) - b = b[end:] - } - return -} - -// fmtDuration returns a string representing d in the form "87.00s". -func fmtDuration(d time.Duration) string { - return fmt.Sprintf("%.2fs", d.Seconds()) -} - -// TB is the interface common to [T], [B], and [F]. -type TB interface { - Attr(key, value string) - Cleanup(func()) - Error(args ...any) - Errorf(format string, args ...any) - Fail() - FailNow() - Failed() bool - Fatal(args ...any) - Fatalf(format string, args ...any) - Helper() - Log(args ...any) - Logf(format string, args ...any) - Name() string - Setenv(key, value string) - Chdir(dir string) - Skip(args ...any) - SkipNow() - Skipf(format string, args ...any) - Skipped() bool - TempDir() string - Context() context.Context - Output() io.Writer - - // A private method to prevent users implementing the - // interface and so future additions to it will not - // violate Go 1 compatibility. - private() -} - -var ( - _ TB = (*T)(nil) - _ TB = (*B)(nil) -) - -// T is a type passed to Test functions to manage test state and support formatted test logs. -// -// A test ends when its Test function returns or calls any of the methods -// [T.FailNow], [T.Fatal], [T.Fatalf], [T.SkipNow], [T.Skip], or [T.Skipf]. Those methods, as well as -// the [T.Parallel] method, must be called only from the goroutine running the -// Test function. -// -// The other reporting methods, such as the variations of [T.Log] and [T.Error], -// may be called simultaneously from multiple goroutines. -type T struct { - common - denyParallel bool - tstate *testState // For running tests and subtests. -} - -func (c *common) private() {} - -// Name returns the name of the running (sub-) test or benchmark. -// -// The name will include the name of the test along with the names of -// any nested sub-tests. If two sibling sub-tests have the same name, -// Name will append a suffix to guarantee the returned name is unique. -func (c *common) Name() string { - return c.name -} - -func (c *common) setRan() { - if c.parent != nil { - c.parent.setRan() - } - c.mu.Lock() - defer c.mu.Unlock() - c.ran = true -} - -// Fail marks the function as having failed but continues execution. -func (c *common) Fail() { - if c.parent != nil { - c.parent.Fail() - } - c.mu.Lock() - defer c.mu.Unlock() - // c.done needs to be locked to synchronize checks to c.done in parent tests. - if c.done { - panic("Fail in goroutine after " + c.name + " has completed") - } - c.failed = true -} - -// Failed reports whether the function has failed. -func (c *common) Failed() bool { - c.mu.RLock() - defer c.mu.RUnlock() - - if !c.done && int64(race.Errors()) > c.lastRaceErrors.Load() { - c.mu.RUnlock() - c.checkRaces() - c.mu.RLock() - } - - return c.failed -} - -// FailNow marks the function as having failed and stops its execution -// by calling [runtime.Goexit] (which then runs all deferred calls in the -// current goroutine). -// Execution will continue at the next test or benchmark. -// FailNow must be called from the goroutine running the -// test or benchmark function, not from other goroutines -// created during the test. Calling FailNow does not stop -// those other goroutines. -func (c *common) FailNow() { - c.checkFuzzFn("FailNow") - c.Fail() - - // Calling runtime.Goexit will exit the goroutine, which - // will run the deferred functions in this goroutine, - // which will eventually run the deferred lines in tRunner, - // which will signal to the test loop that this test is done. - // - // A previous version of this code said: - // - // c.duration = ... - // c.signal <- c.self - // runtime.Goexit() - // - // This previous version duplicated code (those lines are in - // tRunner no matter what), but worse the goroutine teardown - // implicit in runtime.Goexit was not guaranteed to complete - // before the test exited. If a test deferred an important cleanup - // function (like removing temporary files), there was no guarantee - // it would run on a test failure. Because we send on c.signal during - // a top-of-stack deferred function now, we know that the send - // only happens after any other stacked defers have completed. - c.mu.Lock() - c.finished = true - c.mu.Unlock() - runtime.Goexit() -} - -// log generates the output. It is always at the same stack depth. log inserts -// indentation and the final newline if necessary. It prefixes the string -// with the file and line of the call site. -func (c *common) log(s string) { - s = strings.TrimSuffix(s, "\n") - - // Second and subsequent lines are indented 4 spaces. This is in addition to - // the indentation provided by outputWriter. - s = strings.ReplaceAll(s, "\n", "\n"+indent) - s += "\n" - - n := c.destination() - if n == nil { - // The test and all its parents are done. The log cannot be output. - panic("Log in goroutine after " + c.name + " has completed: " + s) - } - - // Prefix with the call site. It is located by skipping 3 functions: - // callSite + log + public function - s = n.callSite(3) + s - - // Output buffered logs. - n.flushPartial() - - n.o.Write([]byte(s)) -} - -// destination selects the test to which output should be appended. It returns the -// test if it is incomplete. Otherwise, it finds its closest incomplete parent. -func (c *common) destination() *common { - c.mu.Lock() - defer c.mu.Unlock() - - if !c.done && !c.isSynctest { - return c - } - for parent := c.parent; parent != nil; parent = parent.parent { - parent.mu.Lock() - defer parent.mu.Unlock() - if !parent.done { - return parent - } - } - return nil -} - -// callSite retrieves and formats the file and line of the call site. -func (c *common) callSite(skip int) string { - c.mu.Lock() - defer c.mu.Unlock() - - frame := c.frameSkip(skip) - file := frame.File - line := frame.Line - if file != "" { - if *fullPath { - // If relative path, truncate file name at last file name separator. - } else { - file = filepath.Base(file) - } - } else { - file = "???" - } - if line == 0 { - line = 1 - } - - return fmt.Sprintf("%s:%d: ", file, line) -} - -// flushPartial checks the buffer for partial logs and outputs them. -func (c *common) flushPartial() { - partial := func() bool { - c.mu.Lock() - defer c.mu.Unlock() - return (c.o != nil) && (len(c.o.partial) > 0) - } - - if partial() { - c.o.Write([]byte("\n")) - } -} - -// Output returns a Writer that writes to the same test output stream as TB.Log. -// The output is indented like TB.Log lines, but Output does not -// add source locations or newlines. The output is internally line -// buffered, and a call to TB.Log or the end of the test will implicitly -// flush the buffer, followed by a newline. After a test function and all its -// parents return, neither Output nor the Write method may be called. -func (c *common) Output() io.Writer { - c.checkFuzzFn("Output") - n := c.destination() - if n == nil { - panic("Output called after " + c.name + " has completed") - } - return n.o -} - -// setOutputWriter initializes an outputWriter and sets it as a common field. -func (c *common) setOutputWriter() { - c.o = &outputWriter{c: c} -} - -// outputWriter buffers, formats and writes log messages. -type outputWriter struct { - c *common - partial []byte // incomplete ('\n'-free) suffix of last Write -} - -// Write writes a log message to the test's output stream, properly formatted and -// indented. It may not be called after a test function and all its parents return. -func (o *outputWriter) Write(p []byte) (int, error) { - // o can be nil if this is called from a top-level *TB that is no longer active. - // Just ignore the message in that case. - if o == nil || o.c == nil { - return 0, nil - } - if o.c.destination() == nil { - panic("Write called after " + o.c.name + " has completed") - } - - o.c.mu.Lock() - defer o.c.mu.Unlock() - - // The last element is a partial line. - lines := bytes.SplitAfter(p, []byte("\n")) - last := len(lines) - 1 // Inv: 0 <= last - for i, line := range lines[:last] { - // Emit partial line from previous call. - if i == 0 && len(o.partial) > 0 { - line = slices.Concat(o.partial, line) - o.partial = o.partial[:0] - } - o.writeLine(line) - } - // Save partial line for next call. - o.partial = append(o.partial, lines[last]...) - - return len(p), nil -} - -// writeLine generates the output for a given line. -func (o *outputWriter) writeLine(b []byte) { - if !o.c.done && (o.c.chatty != nil) { - if o.c.bench { - // Benchmarks don't print === CONT, so we should skip the test - // printer and just print straight to stdout. - fmt.Printf("%s%s", indent, b) - } else { - o.c.chatty.Printf(o.c.name, "%s%s", indent, b) - } - return - } - o.c.output = append(o.c.output, indent...) - o.c.output = append(o.c.output, b...) -} - -// Log formats its arguments using default formatting, analogous to [fmt.Println], -// and records the text in the error log. For tests, the text will be printed only if -// the test fails or the -test.v flag is set. For benchmarks, the text is always -// printed to avoid having performance depend on the value of the -test.v flag. -// It is an error to call Log after a test or benchmark returns. -func (c *common) Log(args ...any) { - c.checkFuzzFn("Log") - c.log(fmt.Sprintln(args...)) -} - -// Logf formats its arguments according to the format, analogous to [fmt.Printf], and -// records the text in the error log. A final newline is added if not provided. For -// tests, the text will be printed only if the test fails or the -test.v flag is -// set. For benchmarks, the text is always printed to avoid having performance -// depend on the value of the -test.v flag. -// It is an error to call Logf after a test or benchmark returns. -func (c *common) Logf(format string, args ...any) { - c.checkFuzzFn("Logf") - c.log(fmt.Sprintf(format, args...)) -} - -// Error is equivalent to Log followed by Fail. -func (c *common) Error(args ...any) { - c.checkFuzzFn("Error") - c.log(fmt.Sprintln(args...)) - c.Fail() -} - -// Errorf is equivalent to Logf followed by Fail. -func (c *common) Errorf(format string, args ...any) { - c.checkFuzzFn("Errorf") - c.log(fmt.Sprintf(format, args...)) - c.Fail() -} - -// Fatal is equivalent to Log followed by FailNow. -func (c *common) Fatal(args ...any) { - c.checkFuzzFn("Fatal") - c.log(fmt.Sprintln(args...)) - c.FailNow() -} - -// Fatalf is equivalent to Logf followed by FailNow. -func (c *common) Fatalf(format string, args ...any) { - c.checkFuzzFn("Fatalf") - c.log(fmt.Sprintf(format, args...)) - c.FailNow() -} - -// Skip is equivalent to Log followed by SkipNow. -func (c *common) Skip(args ...any) { - c.checkFuzzFn("Skip") - c.log(fmt.Sprintln(args...)) - c.SkipNow() -} - -// Skipf is equivalent to Logf followed by SkipNow. -func (c *common) Skipf(format string, args ...any) { - c.checkFuzzFn("Skipf") - c.log(fmt.Sprintf(format, args...)) - c.SkipNow() -} - -// SkipNow marks the test as having been skipped and stops its execution -// by calling [runtime.Goexit]. -// If a test fails (see Error, Errorf, Fail) and is then skipped, -// it is still considered to have failed. -// Execution will continue at the next test or benchmark. See also FailNow. -// SkipNow must be called from the goroutine running the test, not from -// other goroutines created during the test. Calling SkipNow does not stop -// those other goroutines. -func (c *common) SkipNow() { - c.checkFuzzFn("SkipNow") - c.mu.Lock() - c.skipped = true - c.finished = true - c.mu.Unlock() - runtime.Goexit() -} - -// Skipped reports whether the test was skipped. -func (c *common) Skipped() bool { - c.mu.RLock() - defer c.mu.RUnlock() - return c.skipped -} - -// Helper marks the calling function as a test helper function. -// When printing file and line information, that function will be skipped. -// Helper may be called simultaneously from multiple goroutines. -func (c *common) Helper() { - if c.isSynctest { - c = c.parent - } - c.mu.Lock() - defer c.mu.Unlock() - if c.helperPCs == nil { - c.helperPCs = make(map[uintptr]struct{}) - } - // repeating code from callerName here to save walking a stack frame - var pc [1]uintptr - n := runtime.Callers(2, pc[:]) // skip runtime.Callers + Helper - if n == 0 { - panic("testing: zero callers found") - } - if _, found := c.helperPCs[pc[0]]; !found { - c.helperPCs[pc[0]] = struct{}{} - c.helperNames = nil // map will be recreated next time it is needed - } -} - -// Cleanup registers a function to be called when the test (or subtest) and all its -// subtests complete. Cleanup functions will be called in last added, -// first called order. -func (c *common) Cleanup(f func()) { - c.checkFuzzFn("Cleanup") - var pc [maxStackLen]uintptr - // Skip two extra frames to account for this function and runtime.Callers itself. - n := runtime.Callers(2, pc[:]) - cleanupPc := pc[:n] - - fn := func() { - defer func() { - c.mu.Lock() - defer c.mu.Unlock() - c.cleanupName = "" - c.cleanupPc = nil - }() - - name := callerName(0) - c.mu.Lock() - c.cleanupName = name - c.cleanupPc = cleanupPc - c.mu.Unlock() - - f() - } - - c.mu.Lock() - defer c.mu.Unlock() - c.cleanups = append(c.cleanups, fn) -} - -// TempDir returns a temporary directory for the test to use. -// The directory is automatically removed when the test and -// all its subtests complete. -// Each subsequent call to TempDir returns a unique directory; -// if the directory creation fails, TempDir terminates the test by calling Fatal. -func (c *common) TempDir() string { - c.checkFuzzFn("TempDir") - // Use a single parent directory for all the temporary directories - // created by a test, each numbered sequentially. - c.tempDirMu.Lock() - var nonExistent bool - if c.tempDir == "" { // Usually the case with js/wasm - nonExistent = true - } else { - _, err := os.Stat(c.tempDir) - nonExistent = os.IsNotExist(err) - if err != nil && !nonExistent { - c.Fatalf("TempDir: %v", err) - } - } - - if nonExistent { - c.Helper() - - pattern := c.Name() - // Limit length of file names on disk. - // Invalid runes from slicing are dropped by strings.Map below. - pattern = pattern[:min(len(pattern), 64)] - - // Drop unusual characters (such as path separators or - // characters interacting with globs) from the directory name to - // avoid surprising os.MkdirTemp behavior. - mapper := func(r rune) rune { - if r < utf8.RuneSelf { - const allowed = "!#$%&()+,-.=@^_{}~ " - if '0' <= r && r <= '9' || - 'a' <= r && r <= 'z' || - 'A' <= r && r <= 'Z' { - return r - } - if strings.ContainsRune(allowed, r) { - return r - } - } else if unicode.IsLetter(r) || unicode.IsNumber(r) { - return r - } - return -1 - } - pattern = strings.Map(mapper, pattern) - c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern) - if c.tempDirErr == nil { - c.Cleanup(func() { - if err := removeAll(c.tempDir); err != nil { - c.Errorf("TempDir RemoveAll cleanup: %v", err) - } - }) - } - } - - if c.tempDirErr == nil { - c.tempDirSeq++ - } - seq := c.tempDirSeq - c.tempDirMu.Unlock() - - if c.tempDirErr != nil { - c.Fatalf("TempDir: %v", c.tempDirErr) - } - - dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq) - if err := os.Mkdir(dir, 0o777); err != nil { - c.Fatalf("TempDir: %v", err) - } - return dir -} - -// removeAll is like os.RemoveAll, but retries Windows "Access is denied." -// errors up to an arbitrary timeout. -// -// Those errors have been known to occur spuriously on at least the -// windows-amd64-2012 builder (https://go.dev/issue/50051), and can only occur -// legitimately if the test leaves behind a temp file that either is still open -// or the test otherwise lacks permission to delete. In the case of legitimate -// failures, a failing test may take a bit longer to fail, but once the test is -// fixed the extra latency will go away. -func removeAll(path string) error { - const arbitraryTimeout = 2 * time.Second - var ( - start time.Time - nextSleep = 1 * time.Millisecond - ) - for { - err := os.RemoveAll(path) - if !isWindowsRetryable(err) { - return err - } - if start.IsZero() { - start = time.Now() - } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout { - return err - } - time.Sleep(nextSleep) - nextSleep += time.Duration(rand.Int63n(int64(nextSleep))) - } -} - -// Setenv calls [os.Setenv] and uses Cleanup to -// restore the environment variable to its original value -// after the test. -// -// Because Setenv affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (c *common) Setenv(key, value string) { - c.checkFuzzFn("Setenv") - prevValue, ok := os.LookupEnv(key) - - if err := os.Setenv(key, value); err != nil { - c.Fatalf("cannot set environment variable: %v", err) - } - - if ok { - c.Cleanup(func() { - os.Setenv(key, prevValue) - }) - } else { - c.Cleanup(func() { - os.Unsetenv(key) - }) - } -} - -// Chdir calls [os.Chdir] and uses Cleanup to restore the current -// working directory to its original value after the test. On Unix, it -// also sets PWD environment variable for the duration of the test. -// -// Because Chdir affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (c *common) Chdir(dir string) { - c.checkFuzzFn("Chdir") - oldwd, err := os.Open(".") - if err != nil { - c.Fatal(err) - } - if err := os.Chdir(dir); err != nil { - c.Fatal(err) - } - // On POSIX platforms, PWD represents “an absolute pathname of the - // current working directory.” Since we are changing the working - // directory, we should also set or update PWD to reflect that. - switch runtime.GOOS { - case "windows", "plan9": - // Windows and Plan 9 do not use the PWD variable. - default: - if !filepath.IsAbs(dir) { - dir, err = os.Getwd() - if err != nil { - c.Fatal(err) - } - } - c.Setenv("PWD", dir) - } - c.Cleanup(func() { - err := oldwd.Chdir() - oldwd.Close() - if err != nil { - // It's not safe to continue with tests if we can't - // get back to the original working directory. Since - // we are holding a dirfd, this is highly unlikely. - panic("testing.Chdir: " + err.Error()) - } - }) -} - -// Context returns a context that is canceled just before -// Cleanup-registered functions are called. -// -// Cleanup functions can wait for any resources -// that shut down on [context.Context.Done] before the test or benchmark completes. -func (c *common) Context() context.Context { - c.checkFuzzFn("Context") - return c.ctx -} - -// Attr emits a test attribute associated with this test. -// -// The key must not contain whitespace. -// The value must not contain newlines or carriage returns. -// -// The meaning of different attribute keys is left up to -// continuous integration systems and test frameworks. -// -// Test attributes are emitted immediately in the test log, -// but they are intended to be treated as unordered. -func (c *common) Attr(key, value string) { - if strings.ContainsFunc(key, unicode.IsSpace) { - c.Errorf("disallowed whitespace in attribute key %q", key) - return - } - if strings.ContainsAny(value, "\r\n") { - c.Errorf("disallowed newline in attribute value %q", value) - return - } - if c.chatty == nil { - return - } - c.chatty.Updatef(c.name, "=== ATTR %s %v %v\n", c.name, key, value) -} - -// panicHandling controls the panic handling used by runCleanup. -type panicHandling int - -const ( - normalPanic panicHandling = iota - recoverAndReturnPanic -) - -// runCleanup is called at the end of the test. -// If ph is recoverAndReturnPanic, it will catch panics, and return the -// recovered value if any. -func (c *common) runCleanup(ph panicHandling) (panicVal any) { - c.cleanupStarted.Store(true) - defer c.cleanupStarted.Store(false) - - if ph == recoverAndReturnPanic { - defer func() { - panicVal = recover() - }() - } - - // Make sure that if a cleanup function panics, - // we still run the remaining cleanup functions. - defer func() { - c.mu.Lock() - recur := len(c.cleanups) > 0 - c.mu.Unlock() - if recur { - c.runCleanup(normalPanic) - } - }() - - if c.cancelCtx != nil { - c.cancelCtx() - } - - for { - var cleanup func() - c.mu.Lock() - if len(c.cleanups) > 0 { - last := len(c.cleanups) - 1 - cleanup = c.cleanups[last] - c.cleanups = c.cleanups[:last] - } - c.mu.Unlock() - if cleanup == nil { - return nil - } - cleanup() - } -} - -// resetRaces updates c.parent's count of data race errors (or the global count, -// if c has no parent), and updates c.lastRaceErrors to match. -// -// Any races that occurred prior to this call to resetRaces will -// not be attributed to c. -func (c *common) resetRaces() { - if c.parent == nil { - c.lastRaceErrors.Store(int64(race.Errors())) - } else { - c.lastRaceErrors.Store(c.parent.checkRaces()) - } -} - -// checkRaces checks whether the global count of data race errors has increased -// since c's count was last reset. -// -// If so, it marks c as having failed due to those races (logging an error for -// the first such race), and updates the race counts for the parents of c so -// that if they are currently suspended (such as in a call to T.Run) they will -// not log separate errors for the race(s). -// -// Note that multiple tests may be marked as failed due to the same race if they -// are executing in parallel. -func (c *common) checkRaces() (raceErrors int64) { - raceErrors = int64(race.Errors()) - for { - last := c.lastRaceErrors.Load() - if raceErrors <= last { - // All races have already been reported. - return raceErrors - } - if c.lastRaceErrors.CompareAndSwap(last, raceErrors) { - break - } - } - - if c.raceErrorLogged.CompareAndSwap(false, true) { - // This is the first race we've encountered for this test. - // Mark the test as failed, and log the reason why only once. - // (Note that the race detector itself will still write a goroutine - // dump for any further races it detects.) - c.Errorf("race detected during execution of test") - } - - // Update the parent(s) of this test so that they don't re-report the race. - parent := c.parent - for parent != nil { - for { - last := parent.lastRaceErrors.Load() - if raceErrors <= last { - // This race was already reported by another (likely parallel) subtest. - return raceErrors - } - if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) { - break - } - } - parent = parent.parent - } - - return raceErrors -} - -// callerName gives the function name (qualified with a package path) -// for the caller after skip frames (where 0 means the current function). -func callerName(skip int) string { - var pc [1]uintptr - n := runtime.Callers(skip+2, pc[:]) // skip + runtime.Callers + callerName - if n == 0 { - panic("testing: zero callers found") - } - return pcToName(pc[0]) -} - -func pcToName(pc uintptr) string { - pcs := []uintptr{pc} - frames := runtime.CallersFrames(pcs) - frame, _ := frames.Next() - return frame.Function -} - -const parallelConflict = `testing: test using t.Setenv or t.Chdir can not use t.Parallel` - -// Parallel signals that this test is to be run in parallel with (and only with) -// other parallel tests. When a test is run multiple times due to use of -// -test.count or -test.cpu, multiple instances of a single test never run in -// parallel with each other. -func (t *T) Parallel() { - if t.isParallel { - panic("testing: t.Parallel called multiple times") - } - if t.isSynctest { - panic("testing: t.Parallel called inside synctest bubble") - } - if t.denyParallel { - panic(parallelConflict) - } - if t.parent.barrier == nil { - // T.Parallel has no effect when fuzzing. - // Multiple processes may run in parallel, but only one input can run at a - // time per process so we can attribute crashes to specific inputs. - return - } - - t.isParallel = true - - // We don't want to include the time we spend waiting for serial tests - // in the test duration. Record the elapsed time thus far and reset the - // timer afterwards. - t.duration += highPrecisionTimeSince(t.start) - - // Add to the list of tests to be released by the parent. - t.parent.sub = append(t.parent.sub, t) - - // Report any races during execution of this test up to this point. - // - // We will assume that any races that occur between here and the point where - // we unblock are not caused by this subtest. That assumption usually holds, - // although it can be wrong if the test spawns a goroutine that races in the - // background while the rest of the test is blocked on the call to Parallel. - // If that happens, we will misattribute the background race to some other - // test, or to no test at all — but that false-negative is so unlikely that it - // is not worth adding race-report noise for the common case where the test is - // completely suspended during the call to Parallel. - t.checkRaces() - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name) - } - running.Delete(t.name) - - t.signal <- true // Release calling test. - <-t.parent.barrier // Wait for the parent test to complete. - t.tstate.waitParallel() - parallelStart.Add(1) - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== CONT %s\n", t.name) - } - running.Store(t.name, highPrecisionTimeNow()) - t.start = highPrecisionTimeNow() - - // Reset the local race counter to ignore any races that happened while this - // goroutine was blocked, such as in the parent test or in other parallel - // subtests. - // - // (Note that we don't call parent.checkRaces here: - // if other parallel subtests have already introduced races, we want to - // let them report those races instead of attributing them to the parent.) - t.lastRaceErrors.Store(int64(race.Errors())) -} - -func (t *T) checkParallel() { - // Non-parallel subtests that have parallel ancestors may still - // run in parallel with other tests: they are only non-parallel - // with respect to the other subtests of the same parent. - // Since calls like SetEnv or Chdir affects the whole process, we need - // to deny those if the current test or any parent is parallel. - for c := &t.common; c != nil; c = c.parent { - if c.isParallel { - panic(parallelConflict) - } - } - - t.denyParallel = true -} - -// Setenv calls os.Setenv(key, value) and uses Cleanup to -// restore the environment variable to its original value -// after the test. -// -// Because Setenv affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (t *T) Setenv(key, value string) { - t.checkParallel() - t.common.Setenv(key, value) -} - -// Chdir calls [os.Chdir] and uses Cleanup to restore the current -// working directory to its original value after the test. On Unix, it -// also sets PWD environment variable for the duration of the test. -// -// Because Chdir affects the whole process, it cannot be used -// in parallel tests or tests with parallel ancestors. -func (t *T) Chdir(dir string) { - t.checkParallel() - t.common.Chdir(dir) -} - -// InternalTest is an internal type but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -type InternalTest struct { - Name string - F func(*T) -} - -var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit") - -func tRunner(t *T, fn func(t *T)) { - t.runner = callerName(0) - - // When this goroutine is done, either because fn(t) - // returned normally or because a test failure triggered - // a call to runtime.Goexit, record the duration and send - // a signal saying that the test is done. - defer func() { - t.checkRaces() - - // TODO(#61034): This is the wrong place for this check. - if t.Failed() { - numFailed.Add(1) - } - - // Check if the test panicked or Goexited inappropriately. - // - // If this happens in a normal test, print output but continue panicking. - // tRunner is called in its own goroutine, so this terminates the process. - // - // If this happens while fuzzing, recover from the panic and treat it like a - // normal failure. It's important that the process keeps running in order to - // find short inputs that cause panics. - err := recover() - signal := true - - t.mu.RLock() - finished := t.finished - t.mu.RUnlock() - if !finished && err == nil { - err = errNilPanicOrGoexit - for p := t.parent; p != nil; p = p.parent { - p.mu.RLock() - finished = p.finished - p.mu.RUnlock() - if finished { - if !t.isParallel { - t.Errorf("%v: subtest may have called FailNow on a parent test", err) - err = nil - } - signal = false - break - } - } - } - - if err != nil && t.tstate.isFuzzing { - prefix := "panic: " - if err == errNilPanicOrGoexit { - prefix = "" - } - t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack())) - t.mu.Lock() - t.finished = true - t.mu.Unlock() - err = nil - } - - // Use a deferred call to ensure that we report that the test is - // complete even if a cleanup function calls t.FailNow. See issue 41355. - didPanic := false - defer func() { - // Only report that the test is complete if it doesn't panic, - // as otherwise the test binary can exit before the panic is - // reported to the user. See issue 41479. - if didPanic { - return - } - if err != nil { - panic(err) - } - running.Delete(t.name) - if t.isParallel { - parallelStop.Add(1) - } - t.signal <- signal - }() - - doPanic := func(err any) { - t.Fail() - if r := t.runCleanup(recoverAndReturnPanic); r != nil { - t.Logf("cleanup panicked with %v", r) - } - // Flush the output log up to the root before dying. - // Skip this if this *T is a synctest bubble, because we're not a subtest. - for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent { - root.mu.Lock() - root.duration += highPrecisionTimeSince(root.start) - d := root.duration - root.mu.Unlock() - // Output buffered logs. - root.flushPartial() - root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d)) - if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil { - fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r) - } - } - didPanic = true - panic(err) - } - if err != nil { - doPanic(err) - } - - t.duration += highPrecisionTimeSince(t.start) - - if len(t.sub) > 0 { - // Run parallel subtests. - - // Decrease the running count for this test and mark it as no longer running. - t.tstate.release() - running.Delete(t.name) - - // Release the parallel subtests. - close(t.barrier) - // Wait for subtests to complete. - for _, sub := range t.sub { - <-sub.signal - } - - // Run any cleanup callbacks, marking the test as running - // in case the cleanup hangs. - cleanupStart := highPrecisionTimeNow() - running.Store(t.name, cleanupStart) - err := t.runCleanup(recoverAndReturnPanic) - t.duration += highPrecisionTimeSince(cleanupStart) - if err != nil { - doPanic(err) - } - t.checkRaces() - if !t.isParallel { - // Reacquire the count for sequential tests. See comment in Run. - t.tstate.waitParallel() - } - } else if t.isParallel { - // Only release the count for this test if it was run as a parallel - // test. See comment in Run method. - t.tstate.release() - } - // Output buffered logs. - for root := &t.common; root.parent != nil; root = root.parent { - root.flushPartial() - } - t.report() // Report after all subtests have finished. - - // Do not lock t.done to allow race detector to detect race in case - // the user does not appropriately synchronize a goroutine. - t.done = true - if t.parent != nil && !t.hasSub.Load() { - t.setRan() - } - }() - defer func() { - if len(t.sub) == 0 { - t.runCleanup(normalPanic) - } - }() - - t.start = highPrecisionTimeNow() - t.resetRaces() - fn(t) - - // code beyond here will not be executed when FailNow is invoked - t.mu.Lock() - t.finished = true - t.mu.Unlock() -} - -// Run runs f as a subtest of t called name. It runs f in a separate goroutine -// and blocks until f returns or calls t.Parallel to become a parallel test. -// Run reports whether f succeeded (or at least did not fail before calling t.Parallel). -// -// Run may be called simultaneously from multiple goroutines, but all such calls -// must return before the outer test function for t returns. -func (t *T) Run(name string, f func(t *T)) bool { - if t.isSynctest { - panic("testing: t.Run called inside synctest bubble") - } - if t.cleanupStarted.Load() { - panic("testing: t.Run called during t.Cleanup") - } - - t.hasSub.Store(true) - testName, ok, _ := t.tstate.match.fullName(&t.common, name) - if !ok || shouldFailFast() { - return true - } - // Record the stack trace at the point of this call so that if the subtest - // function - which runs in a separate stack - is marked as a helper, we can - // continue walking the stack into the parent test. - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - - // There's no reason to inherit this context from parent. The user's code can't observe - // the difference between the background context and the one from the parent test. - ctx, cancelCtx := context.WithCancel(context.Background()) - t = &T{ - common: common{ - barrier: make(chan bool), - signal: make(chan bool, 1), - name: testName, - parent: &t.common, - level: t.level + 1, - creator: pc[:n], - chatty: t.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: t.tstate, - } - t.w = indenter{&t.common} - t.setOutputWriter() - - if t.chatty != nil { - t.chatty.Updatef(t.name, "=== RUN %s\n", t.name) - } - running.Store(t.name, highPrecisionTimeNow()) - - // Instead of reducing the running count of this test before calling the - // tRunner and increasing it afterwards, we rely on tRunner keeping the - // count correct. This ensures that a sequence of sequential tests runs - // without being preempted, even when their parent is a parallel test. This - // may especially reduce surprises if *parallel == 1. - go tRunner(t, f) - - // The parent goroutine will block until the subtest either finishes or calls - // Parallel, but in general we don't know whether the parent goroutine is the - // top-level test function or some other goroutine it has spawned. - // To avoid confusing false-negatives, we leave the parent in the running map - // even though in the typical case it is blocked. - - if !<-t.signal { - // At this point, it is likely that FailNow was called on one of the - // parent tests by one of the subtests. Continue aborting up the chain. - runtime.Goexit() - } - - if t.chatty != nil && t.chatty.json { - t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name) - } - return !t.failed -} - -// testingSynctestTest runs f within a synctest bubble. -// It is called by synctest.Test, from within an already-created bubble. -// -//go:linkname testingSynctestTest testing/synctest.testingSynctestTest -func testingSynctestTest(t *T, f func(*T)) (ok bool) { - if t.cleanupStarted.Load() { - panic("testing: synctest.Run called during t.Cleanup") - } - - var pc [maxStackLen]uintptr - n := runtime.Callers(2, pc[:]) - - ctx, cancelCtx := context.WithCancel(context.Background()) - t2 := &T{ - common: common{ - barrier: make(chan bool), - signal: make(chan bool, 1), - name: t.name, - parent: &t.common, - level: t.level + 1, - creator: pc[:n], - chatty: t.chatty, - ctx: ctx, - cancelCtx: cancelCtx, - isSynctest: true, - }, - tstate: t.tstate, - } - - go tRunner(t2, f) - if !<-t2.signal { - // At this point, it is likely that FailNow was called on one of the - // parent tests by one of the subtests. Continue aborting up the chain. - runtime.Goexit() - } - return !t2.failed -} - -// Deadline reports the time at which the test binary will have -// exceeded the timeout specified by the -timeout flag. -// -// The ok result is false if the -timeout flag indicates “no timeout” (0). -func (t *T) Deadline() (deadline time.Time, ok bool) { - if t.isSynctest { - // There's no point in returning a real-clock deadline to - // a test using a fake clock. We could return "no timeout", - // but panicking makes it easier for users to catch the error. - panic("testing: t.Deadline called inside synctest bubble") - } - deadline = t.tstate.deadline - return deadline, !deadline.IsZero() -} - -// testState holds all fields that are common to all tests. This includes -// synchronization primitives to run at most *parallel tests. -type testState struct { - match *matcher - deadline time.Time - - // isFuzzing is true in the state used when generating random inputs - // for fuzz targets. isFuzzing is false when running normal tests and - // when running fuzz tests as unit tests (without -fuzz or when -fuzz - // does not match). - isFuzzing bool - - mu sync.Mutex - - // Channel used to signal tests that are ready to be run in parallel. - startParallel chan bool - - // running is the number of tests currently running in parallel. - // This does not include tests that are waiting for subtests to complete. - running int - - // numWaiting is the number tests waiting to be run in parallel. - numWaiting int - - // maxParallel is a copy of the parallel flag. - maxParallel int -} - -func newTestState(maxParallel int, m *matcher) *testState { - return &testState{ - match: m, - startParallel: make(chan bool), - maxParallel: maxParallel, - running: 1, // Set the count to 1 for the main (sequential) test. - } -} - -func (s *testState) waitParallel() { - s.mu.Lock() - if s.running < s.maxParallel { - s.running++ - s.mu.Unlock() - return - } - s.numWaiting++ - s.mu.Unlock() - <-s.startParallel -} - -func (s *testState) release() { - s.mu.Lock() - if s.numWaiting == 0 { - s.running-- - s.mu.Unlock() - return - } - s.numWaiting-- - s.mu.Unlock() - s.startParallel <- true // Pick a waiting test to be run. -} - -// No one should be using func Main anymore. -// See the doc comment on func Main and use MainStart instead. -var errMain = errors.New("testing: unexpected use of func Main") - -type matchStringOnly func(pat, str string) (bool, error) - -func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) } -func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain } -func (f matchStringOnly) StopCPUProfile() {} -func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain } -func (f matchStringOnly) ImportPath() string { return "" } -func (f matchStringOnly) StartTestLog(io.Writer) {} -func (f matchStringOnly) StopTestLog() error { return errMain } -func (f matchStringOnly) SetPanicOnExit0(bool) {} -func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error { - return errMain -} -func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain } -func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) { - return nil, errMain -} -func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil } -func (f matchStringOnly) ResetCoverage() {} -func (f matchStringOnly) SnapshotCoverage() {} - -func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) { - return -} - -// Main is an internal function, part of the implementation of the "go test" command. -// It was exported because it is cross-package and predates "internal" packages. -// It is no longer used by "go test" but preserved, as much as possible, for other -// systems that simulate "go test" using Main, but Main sometimes cannot be updated as -// new functionality is added to the testing package. -// Systems simulating "go test" should be updated to use [MainStart]. -func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) { - os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run()) -} - -// M is a type passed to a TestMain function to run the actual tests. -type M struct { - deps testDeps - tests []InternalTest - benchmarks []InternalBenchmark - fuzzTargets []InternalFuzzTarget - examples []InternalExample - - timer *time.Timer - afterOnce sync.Once - - numRun int - - // value to pass to os.Exit, the outer test func main - // harness calls os.Exit with this code. See #34129. - exitCode int -} - -// testDeps is an internal interface of functionality that is -// passed into this package by a test's generated main package. -// The canonical implementation of this interface is -// testing/internal/testdeps's TestDeps. -type testDeps interface { - ImportPath() string - MatchString(pat, str string) (bool, error) - SetPanicOnExit0(bool) - StartCPUProfile(io.Writer) error - StopCPUProfile() - StartTestLog(io.Writer) - StopTestLog() error - WriteProfileTo(string, io.Writer, int) error - CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error - RunFuzzWorker(func(corpusEntry) error) error - ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) - CheckCorpus([]any, []reflect.Type) error - ResetCoverage() - SnapshotCoverage() - InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) -} - -// MainStart is meant for use by tests generated by 'go test'. -// It is not meant to be called directly and is not subject to the Go 1 compatibility document. -// It may change signature from release to release. -func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M { - registerCover(deps.InitRuntimeCoverage()) - Init() - return &M{ - deps: deps, - tests: tests, - benchmarks: benchmarks, - fuzzTargets: fuzzTargets, - examples: examples, - } -} - -var ( - testingTesting bool - realStderr *os.File -) - -// Run runs the tests. It returns an exit code to pass to os.Exit. -// The exit code is zero when all tests pass, and non-zero for any kind -// of failure. For machine readable test results, parse the output of -// 'go test -json'. -func (m *M) Run() (code int) { - defer func() { - code = m.exitCode - }() - - // Count the number of calls to m.Run. - // We only ever expected 1, but we didn't enforce that, - // and now there are tests in the wild that call m.Run multiple times. - // Sigh. go.dev/issue/23129. - m.numRun++ - - // TestMain may have already called flag.Parse. - if !flag.Parsed() { - flag.Parse() - } - - if chatty.json { - // With -v=json, stdout and stderr are pointing to the same pipe, - // which is leading into test2json. In general, operating systems - // do a good job of ensuring that writes to the same pipe through - // different file descriptors are delivered whole, so that writing - // AAA to stdout and BBB to stderr simultaneously produces - // AAABBB or BBBAAA on the pipe, not something like AABBBA. - // However, the exception to this is when the pipe fills: in that - // case, Go's use of non-blocking I/O means that writing AAA - // or BBB might be split across multiple system calls, making it - // entirely possible to get output like AABBBA. The same problem - // happens inside the operating system kernel if we switch to - // blocking I/O on the pipe. This interleaved output can do things - // like print unrelated messages in the middle of a TestFoo line, - // which confuses test2json. Setting os.Stderr = os.Stdout will make - // them share a single pfd, which will hold a lock for each program - // write, preventing any interleaving. - // - // It might be nice to set Stderr = Stdout always, or perhaps if - // we can tell they are the same file, but for now -v=json is - // a very clear signal. Making the two files the same may cause - // surprises if programs close os.Stdout but expect to be able - // to continue to write to os.Stderr, but it's hard to see why a - // test would think it could take over global state that way. - // - // This fix only helps programs where the output is coming directly - // from Go code. It does not help programs in which a subprocess is - // writing to stderr or stdout at the same time that a Go test is writing output. - // It also does not help when the output is coming from the runtime, - // such as when using the print/println functions, since that code writes - // directly to fd 2 without any locking. - // We keep realStderr around to prevent fd 2 from being closed. - // - // See go.dev/issue/33419. - realStderr = os.Stderr - os.Stderr = os.Stdout - } - - if *parallel < 1 { - fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer") - flag.Usage() - m.exitCode = 2 - return - } - if *matchFuzz != "" && *fuzzCacheDir == "" { - fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set") - flag.Usage() - m.exitCode = 2 - return - } - - if *matchList != "" { - listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples) - m.exitCode = 0 - return - } - - if *shuffle != "off" { - var n int64 - var err error - if *shuffle == "on" { - n = time.Now().UnixNano() - } else { - n, err = strconv.ParseInt(*shuffle, 10, 64) - if err != nil { - fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err) - m.exitCode = 2 - return - } - } - fmt.Println("-test.shuffle", n) - rng := rand.New(rand.NewSource(n)) - rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] }) - rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] }) - } - - parseCpuList() - - m.before() - defer m.after() - - // Run tests, examples, and benchmarks unless this is a fuzz worker process. - // Workers start after this is done by their parent process, and they should - // not repeat this work. - if !*isFuzzWorker { - deadline := m.startAlarm() - haveExamples = len(m.examples) > 0 - testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline) - fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline) - exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples) - m.stopAlarm() - if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" { - fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") - if testingTesting && *match != "^$" { - // If this happens during testing of package testing it could be that - // package testing's own logic for when to run a test is broken, - // in which case every test will run nothing and succeed, - // with no obvious way to detect this problem (since no tests are running). - // So make 'no tests to run' a hard failure when testing package testing itself. - fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n") - testOk = false - } - } - anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) - if !anyFailed && race.Errors() > 0 { - fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n") - anyFailed = true - } - if anyFailed { - fmt.Print(chatty.prefix(), "FAIL\n") - m.exitCode = 1 - return - } - } - - fuzzingOk := runFuzzing(m.deps, m.fuzzTargets) - if !fuzzingOk { - fmt.Print(chatty.prefix(), "FAIL\n") - if *isFuzzWorker { - m.exitCode = fuzzWorkerExitCode - } else { - m.exitCode = 1 - } - return - } - - m.exitCode = 0 - if !*isFuzzWorker { - fmt.Print(chatty.prefix(), "PASS\n") - } - return -} - -func (t *T) report() { - if t.parent == nil { - return - } - if t.isSynctest { - return // t.parent will handle reporting - } - dstr := fmtDuration(t.duration) - format := "--- %s: %s (%s)\n" - if t.Failed() { - t.flushToParent(t.name, format, "FAIL", t.name, dstr) - } else if t.chatty != nil { - if t.Skipped() { - t.flushToParent(t.name, format, "SKIP", t.name, dstr) - } else { - t.flushToParent(t.name, format, "PASS", t.name, dstr) - } - } -} - -func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) { - if _, err := matchString(*matchList, "non-empty"); err != nil { - fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err) - os.Exit(1) - } - - for _, test := range tests { - if ok, _ := matchString(*matchList, test.Name); ok { - fmt.Println(test.Name) - } - } - for _, bench := range benchmarks { - if ok, _ := matchString(*matchList, bench.Name); ok { - fmt.Println(bench.Name) - } - } - for _, fuzzTarget := range fuzzTargets { - if ok, _ := matchString(*matchList, fuzzTarget.Name); ok { - fmt.Println(fuzzTarget.Name) - } - } - for _, example := range examples { - if ok, _ := matchString(*matchList, example.Name); ok { - fmt.Println(example.Name) - } - } -} - -// RunTests is an internal function but exported because it is cross-package; -// it is part of the implementation of the "go test" command. -func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) { - var deadline time.Time - if *timeout > 0 { - deadline = time.Now().Add(*timeout) - } - ran, ok := runTests(matchString, tests, deadline) - if !ran && !haveExamples { - fmt.Fprintln(os.Stderr, "testing: warning: no tests to run") - } - return ok -} - -func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) { - ok = true - for _, procs := range cpuList { - runtime.GOMAXPROCS(procs) - for i := uint(0); i < *count; i++ { - if shouldFailFast() { - break - } - if i > 0 && !ran { - // There were no tests to run on the first - // iteration. This won't change, so no reason - // to keep trying. - break - } - ctx, cancelCtx := context.WithCancel(context.Background()) - tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip)) - tstate.deadline = deadline - t := &T{ - common: common{ - signal: make(chan bool, 1), - barrier: make(chan bool), - w: os.Stdout, - ctx: ctx, - cancelCtx: cancelCtx, - }, - tstate: tstate, - } - if Verbose() { - t.chatty = newChattyPrinter(t.w) - } - tRunner(t, func(t *T) { - for _, test := range tests { - t.Run(test.Name, test.F) - } - }) - select { - case <-t.signal: - default: - panic("internal error: tRunner exited without sending on t.signal") - } - ok = ok && !t.Failed() - ran = ran || t.ran - } - } - return ran, ok -} - -// before runs before all testing. -func (m *M) before() { - if *memProfileRate > 0 { - runtime.MemProfileRate = *memProfileRate - } - if *cpuProfile != "" { - f, err := os.Create(toOutputDir(*cpuProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - return - } - if err := m.deps.StartCPUProfile(f); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err) - f.Close() - return - } - // Could save f so after can call f.Close; not worth the effort. - } - if *traceFile != "" { - f, err := os.Create(toOutputDir(*traceFile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - return - } - if err := trace.Start(f); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err) - f.Close() - return - } - // Could save f so after can call f.Close; not worth the effort. - } - if *blockProfile != "" && *blockProfileRate >= 0 { - runtime.SetBlockProfileRate(*blockProfileRate) - } - if *mutexProfile != "" && *mutexProfileFraction >= 0 { - runtime.SetMutexProfileFraction(*mutexProfileFraction) - } - if *coverProfile != "" && CoverMode() == "" { - fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n") - os.Exit(2) - } - if *gocoverdir != "" && CoverMode() == "" { - fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n") - os.Exit(2) - } - if *testlog != "" { - // Note: Not using toOutputDir. - // This file is for use by cmd/go, not users. - var f *os.File - var err error - if m.numRun == 1 { - f, err = os.Create(*testlog) - } else { - f, err = os.OpenFile(*testlog, os.O_WRONLY, 0) - if err == nil { - f.Seek(0, io.SeekEnd) - } - } - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - m.deps.StartTestLog(f) - testlogFile = f - } - if *panicOnExit0 { - m.deps.SetPanicOnExit0(true) - } -} - -// after runs after all testing. -func (m *M) after() { - m.afterOnce.Do(func() { - m.writeProfiles() - }) - - // Restore PanicOnExit0 after every run, because we set it to true before - // every run. Otherwise, if m.Run is called multiple times the behavior of - // os.Exit(0) will not be restored after the second run. - if *panicOnExit0 { - m.deps.SetPanicOnExit0(false) - } -} - -func (m *M) writeProfiles() { - if *testlog != "" { - if err := m.deps.StopTestLog(); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err) - os.Exit(2) - } - if err := testlogFile.Close(); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err) - os.Exit(2) - } - } - if *cpuProfile != "" { - m.deps.StopCPUProfile() // flushes profile to disk - } - if *traceFile != "" { - trace.Stop() // flushes trace to disk - } - if *memProfile != "" { - f, err := os.Create(toOutputDir(*memProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - runtime.GC() // materialize all statistics - if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err) - os.Exit(2) - } - f.Close() - } - if *blockProfile != "" && *blockProfileRate >= 0 { - f, err := os.Create(toOutputDir(*blockProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - if err = m.deps.WriteProfileTo("block", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err) - os.Exit(2) - } - f.Close() - } - if *mutexProfile != "" && *mutexProfileFraction >= 0 { - f, err := os.Create(toOutputDir(*mutexProfile)) - if err != nil { - fmt.Fprintf(os.Stderr, "testing: %s\n", err) - os.Exit(2) - } - if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil { - fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err) - os.Exit(2) - } - f.Close() - } - if CoverMode() != "" { - coverReport() - } -} - -// toOutputDir returns the file name relocated, if required, to outputDir. -// Simple implementation to avoid pulling in path/filepath. -func toOutputDir(path string) string { - if *outputDir == "" || path == "" { - return path - } - // On Windows, it's clumsy, but we can be almost always correct - // by just looking for a drive letter and a colon. - // Absolute paths always have a drive letter (ignoring UNC). - // Problem: if path == "C:A" and outputdir == "C:\Go" it's unclear - // what to do, but even then path/filepath doesn't help. - // TODO: Worth doing better? Probably not, because we're here only - // under the management of go test. - if runtime.GOOS == "windows" && len(path) >= 2 { - letter, colon := path[0], path[1] - if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' { - // If path starts with a drive letter we're stuck with it regardless. - return path - } - } - if os.IsPathSeparator(path[0]) { - return path - } - return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path) -} - -// startAlarm starts an alarm if requested. -func (m *M) startAlarm() time.Time { - if *timeout <= 0 { - return time.Time{} - } - - deadline := time.Now().Add(*timeout) - m.timer = time.AfterFunc(*timeout, func() { - m.after() - debug.SetTraceback("all") - extra := "" - - if list := runningList(); len(list) > 0 { - var b strings.Builder - b.WriteString("\nrunning tests:") - for _, name := range list { - b.WriteString("\n\t") - b.WriteString(name) - } - extra = b.String() - } - panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra)) - }) - return deadline -} - -// runningList returns the list of running tests. -func runningList() []string { - var list []string - running.Range(func(k, v any) bool { - list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second))) - return true - }) - slices.Sort(list) - return list -} - -// stopAlarm turns off the alarm. -func (m *M) stopAlarm() { - if *timeout > 0 { - m.timer.Stop() - } -} - -func parseCpuList() { - for val := range strings.SplitSeq(*cpuListStr, ",") { - val = strings.TrimSpace(val) - if val == "" { - continue - } - cpu, err := strconv.Atoi(val) - if err != nil || cpu <= 0 { - fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val) - os.Exit(1) - } - cpuList = append(cpuList, cpu) - } - if cpuList == nil { - cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) - } -} - -func shouldFailFast() bool { - return *failFast && numFailed.Load() > 0 -} diff --git a/testing/testing/testing_other.go b/testing/testing/testing_other.go deleted file mode 100644 index f91e3b4a..00000000 --- a/testing/testing/testing_other.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2021 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 !windows - -package testing - -import "time" - -// isWindowsRetryable reports whether err is a Windows error code -// that may be fixed by retrying a failed filesystem operation. -func isWindowsRetryable(err error) bool { - return false -} - -// highPrecisionTime represents a single point in time. -// On all systems except Windows, using time.Time is fine. -type highPrecisionTime struct { - now time.Time -} - -// highPrecisionTimeNow returns high precision time for benchmarking. -func highPrecisionTimeNow() highPrecisionTime { - return highPrecisionTime{now: time.Now()} -} - -// highPrecisionTimeSince returns duration since b. -func highPrecisionTimeSince(b highPrecisionTime) time.Duration { - return time.Since(b.now) -} diff --git a/testing/testing/testing_test.go b/testing/testing/testing_test.go deleted file mode 100644 index d7096d43..00000000 --- a/testing/testing/testing_test.go +++ /dev/null @@ -1,1079 +0,0 @@ -// Copyright 2014 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" - "context" - "errors" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/race" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/testenv" - "os" - "os/exec" - "path/filepath" - "regexp" - "runtime" - "slices" - "strings" - "sync" - "testing" - "time" -) - -// This is exactly what a test would do without a TestMain. -// It's here only so that there is at least one package in the -// standard library with a TestMain, so that code is executed. - -func TestMain(m *testing.M) { - if os.Getenv("GO_WANT_RACE_BEFORE_TESTS") == "1" { - doRace() - } - - m.Run() - - // Note: m.Run currently prints the final "PASS" line, so if any race is - // reported here (after m.Run but before the process exits), it will print - // "PASS", then print the stack traces for the race, then exit with nonzero - // status. - // - // This is a somewhat fundamental race: because the race detector hooks into - // the runtime at a very low level, no matter where we put the printing it - // would be possible to report a race that occurs afterward. However, we could - // theoretically move the printing after TestMain, which would at least do a - // better job of diagnosing races in cleanup functions within TestMain itself. -} - -func TestTempDirInCleanup(t *testing.T) { - var dir string - - t.Run("test", func(t *testing.T) { - t.Cleanup(func() { - dir = t.TempDir() - }) - _ = t.TempDir() - }) - - fi, err := os.Stat(dir) - if fi != nil { - t.Fatalf("Directory %q from user Cleanup still exists", dir) - } - if !os.IsNotExist(err) { - t.Fatalf("Unexpected error: %v", err) - } -} - -func TestTempDirInBenchmark(t *testing.T) { - testing.Benchmark(func(b *testing.B) { - if !b.Run("test", func(b *testing.B) { - // Add a loop so that the test won't fail. See issue 38677. - for i := 0; i < b.N; i++ { - _ = b.TempDir() - } - }) { - t.Fatal("Sub test failure in a benchmark") - } - }) -} - -func TestTempDir(t *testing.T) { - testTempDir(t) - t.Run("InSubtest", testTempDir) - t.Run("test/subtest", testTempDir) - t.Run("test\\subtest", testTempDir) - t.Run("test:subtest", testTempDir) - t.Run("test/..", testTempDir) - t.Run("../test", testTempDir) - t.Run("test[]", testTempDir) - t.Run("test*", testTempDir) - t.Run("äöüéè", testTempDir) - t.Run(strings.Repeat("a", 300), testTempDir) -} - -func testTempDir(t *testing.T) { - dirCh := make(chan string, 1) - t.Cleanup(func() { - // Verify directory has been removed. - select { - case dir := <-dirCh: - fi, err := os.Stat(dir) - if os.IsNotExist(err) { - // All good - return - } - if err != nil { - t.Fatal(err) - } - t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir()) - default: - if !t.Failed() { - t.Fatal("never received dir channel") - } - } - }) - - dir := t.TempDir() - if dir == "" { - t.Fatal("expected dir") - } - dir2 := t.TempDir() - if dir == dir2 { - t.Fatal("subsequent calls to TempDir returned the same directory") - } - if filepath.Dir(dir) != filepath.Dir(dir2) { - t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2) - } - dirCh <- dir - fi, err := os.Stat(dir) - if err != nil { - t.Fatal(err) - } - if !fi.IsDir() { - t.Errorf("dir %q is not a dir", dir) - } - files, err := os.ReadDir(dir) - if err != nil { - t.Fatal(err) - } - if len(files) > 0 { - t.Errorf("unexpected %d files in TempDir: %v", len(files), files) - } - - glob := filepath.Join(dir, "*.txt") - if _, err := filepath.Glob(glob); err != nil { - t.Error(err) - } -} - -func TestSetenv(t *testing.T) { - tests := []struct { - name string - key string - initialValueExists bool - initialValue string - newValue string - }{ - { - name: "initial value exists", - key: "GO_TEST_KEY_1", - initialValueExists: true, - initialValue: "111", - newValue: "222", - }, - { - name: "initial value exists but empty", - key: "GO_TEST_KEY_2", - initialValueExists: true, - initialValue: "", - newValue: "222", - }, - { - name: "initial value is not exists", - key: "GO_TEST_KEY_3", - initialValueExists: false, - initialValue: "", - newValue: "222", - }, - } - - for _, test := range tests { - if test.initialValueExists { - if err := os.Setenv(test.key, test.initialValue); err != nil { - t.Fatalf("unable to set env: got %v", err) - } - } else { - os.Unsetenv(test.key) - } - - t.Run(test.name, func(t *testing.T) { - t.Setenv(test.key, test.newValue) - if os.Getenv(test.key) != test.newValue { - t.Fatalf("unexpected value after t.Setenv: got %s, want %s", os.Getenv(test.key), test.newValue) - } - }) - - got, exists := os.LookupEnv(test.key) - if got != test.initialValue { - t.Fatalf("unexpected value after t.Setenv cleanup: got %s, want %s", got, test.initialValue) - } - if exists != test.initialValueExists { - t.Fatalf("unexpected value after t.Setenv cleanup: got %t, want %t", exists, test.initialValueExists) - } - } -} - -func expectParallelConflict(t *testing.T) { - want := testing.ParallelConflict - if got := recover(); got != want { - t.Fatalf("expected panic; got %#v want %q", got, want) - } -} - -func testWithParallelAfter(t *testing.T, fn func(*testing.T)) { - defer expectParallelConflict(t) - - fn(t) - t.Parallel() -} - -func testWithParallelBefore(t *testing.T, fn func(*testing.T)) { - defer expectParallelConflict(t) - - t.Parallel() - fn(t) -} - -func testWithParallelParentBefore(t *testing.T, fn func(*testing.T)) { - t.Parallel() - - t.Run("child", func(t *testing.T) { - defer expectParallelConflict(t) - - fn(t) - }) -} - -func testWithParallelGrandParentBefore(t *testing.T, fn func(*testing.T)) { - t.Parallel() - - t.Run("child", func(t *testing.T) { - t.Run("grand-child", func(t *testing.T) { - defer expectParallelConflict(t) - - fn(t) - }) - }) -} - -func tSetenv(t *testing.T) { - t.Setenv("GO_TEST_KEY_1", "value") -} - -func TestSetenvWithParallelAfter(t *testing.T) { - testWithParallelAfter(t, tSetenv) -} - -func TestSetenvWithParallelBefore(t *testing.T) { - testWithParallelBefore(t, tSetenv) -} - -func TestSetenvWithParallelParentBefore(t *testing.T) { - testWithParallelParentBefore(t, tSetenv) -} - -func TestSetenvWithParallelGrandParentBefore(t *testing.T) { - testWithParallelGrandParentBefore(t, tSetenv) -} - -func tChdir(t *testing.T) { - t.Chdir(t.TempDir()) -} - -func TestChdirWithParallelAfter(t *testing.T) { - testWithParallelAfter(t, tChdir) -} - -func TestChdirWithParallelBefore(t *testing.T) { - testWithParallelBefore(t, tChdir) -} - -func TestChdirWithParallelParentBefore(t *testing.T) { - testWithParallelParentBefore(t, tChdir) -} - -func TestChdirWithParallelGrandParentBefore(t *testing.T) { - testWithParallelGrandParentBefore(t, tChdir) -} - -func TestChdir(t *testing.T) { - oldDir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - defer os.Chdir(oldDir) - - // The "relative" test case relies on tmp not being a symlink. - tmp, err := filepath.EvalSymlinks(t.TempDir()) - if err != nil { - t.Fatal(err) - } - rel, err := filepath.Rel(oldDir, tmp) - if err != nil { - // If GOROOT is on C: volume and tmp is on the D: volume, there - // is no relative path between them, so skip that test case. - rel = "skip" - } - - for _, tc := range []struct { - name, dir, pwd string - extraChdir bool - }{ - { - name: "absolute", - dir: tmp, - pwd: tmp, - }, - { - name: "relative", - dir: rel, - pwd: tmp, - }, - { - name: "current (absolute)", - dir: oldDir, - pwd: oldDir, - }, - { - name: "current (relative) with extra os.Chdir", - dir: ".", - pwd: oldDir, - - extraChdir: true, - }, - } { - t.Run(tc.name, func(t *testing.T) { - if tc.dir == "skip" { - t.Skipf("skipping test because there is no relative path between %s and %s", oldDir, tmp) - } - if !filepath.IsAbs(tc.pwd) { - t.Fatalf("Bad tc.pwd: %q (must be absolute)", tc.pwd) - } - - t.Chdir(tc.dir) - - newDir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - if newDir != tc.pwd { - t.Fatalf("failed to chdir to %q: getwd: got %q, want %q", tc.dir, newDir, tc.pwd) - } - - switch runtime.GOOS { - case "windows", "plan9": - // Windows and Plan 9 do not use the PWD variable. - default: - if pwd := os.Getenv("PWD"); pwd != tc.pwd { - t.Fatalf("PWD: got %q, want %q", pwd, tc.pwd) - } - } - - if tc.extraChdir { - os.Chdir("..") - } - }) - - newDir, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - if newDir != oldDir { - t.Fatalf("failed to restore wd to %s: getwd: %s", oldDir, newDir) - } - } -} - -// testingTrueInInit is part of TestTesting. -var testingTrueInInit = false - -// testingTrueInPackageVarInit is part of TestTesting. -var testingTrueInPackageVarInit = testing.Testing() - -// init is part of TestTesting. -func init() { - if testing.Testing() { - testingTrueInInit = true - } -} - -var testingProg = ` -package main - -import ( - "fmt" - "testing" -) - -func main() { - fmt.Println(testing.Testing()) -} -` - -func TestTesting(t *testing.T) { - if !testing.Testing() { - t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true) - } - if !testingTrueInInit { - t.Errorf("testing.Testing() called by init function == %t, want %t", testingTrueInInit, true) - } - if !testingTrueInPackageVarInit { - t.Errorf("testing.Testing() variable initialized as %t, want %t", testingTrueInPackageVarInit, true) - } - - if testing.Short() { - t.Skip("skipping building a binary in short mode") - } - testenv.MustHaveGoRun(t) - - fn := filepath.Join(t.TempDir(), "x.go") - if err := os.WriteFile(fn, []byte(testingProg), 0644); err != nil { - t.Fatal(err) - } - - cmd := testenv.Command(t, testenv.GoToolPath(t), "run", fn) - out, err := cmd.CombinedOutput() - if err != nil { - t.Fatalf("%v failed: %v\n%s", cmd, err, out) - } - - s := string(bytes.TrimSpace(out)) - if s != "false" { - t.Errorf("in non-test testing.Test() returned %q, want %q", s, "false") - } -} - -// runTest runs a helper test with -test.v, ignoring its exit status. -// runTest both logs and returns the test output. -func runTest(t *testing.T, test string) []byte { - t.Helper() - - testenv.MustHaveExec(t) - - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+test+"$", "-test.bench="+test, "-test.v", "-test.parallel=2", "-test.benchtime=2x") - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1") - out, err := cmd.CombinedOutput() - t.Logf("%v: %v\n%s", cmd, err, out) - - return out -} - -// doRace provokes a data race that generates a race detector report if run -// under the race detector and is otherwise benign. -func doRace() { - var x int - c1 := make(chan bool) - go func() { - x = 1 // racy write - c1 <- true - }() - _ = x // racy read - <-c1 -} - -func TestRaceReports(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - // Generate a race detector report in a sub test. - t.Run("Sub", func(t *testing.T) { - doRace() - }) - return - } - - out := runTest(t, "TestRaceReports") - - // We should see at most one race detector report. - c := bytes.Count(out, []byte("race detected")) - want := 0 - if race.Enabled { - want = 1 - } - if c != want { - t.Errorf("got %d race reports, want %d", c, want) - } -} - -// Issue #60083. This used to fail on the race builder. -func TestRaceName(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - doRace() - return - } - - out := runTest(t, "TestRaceName") - - if regexp.MustCompile(`=== NAME\s*$`).Match(out) { - t.Errorf("incorrectly reported test with no name") - } -} - -func TestRaceSubReports(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - t.Parallel() - c1 := make(chan bool, 1) - t.Run("sub", func(t *testing.T) { - t.Run("subsub1", func(t *testing.T) { - t.Parallel() - doRace() - c1 <- true - }) - t.Run("subsub2", func(t *testing.T) { - t.Parallel() - doRace() - <-c1 - }) - }) - doRace() - return - } - - out := runTest(t, "TestRaceSubReports") - - // There should be three race reports: one for each subtest, and one for the - // race after the subtests complete. Note that because the subtests run in - // parallel, the race stacks may both be printed in with one or the other - // test's logs. - cReport := bytes.Count(out, []byte("race detected during execution of test")) - wantReport := 0 - if race.Enabled { - wantReport = 3 - } - if cReport != wantReport { - t.Errorf("got %d race reports, want %d", cReport, wantReport) - } - - // Regardless of when the stacks are printed, we expect each subtest to be - // marked as failed, and that failure should propagate up to the parents. - cFail := bytes.Count(out, []byte("--- FAIL:")) - wantFail := 0 - if race.Enabled { - wantFail = 4 - } - if cFail != wantFail { - t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport) - } -} - -func TestRaceInCleanup(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - t.Cleanup(doRace) - t.Parallel() - t.Run("sub", func(t *testing.T) { - t.Parallel() - // No race should be reported for sub. - }) - return - } - - out := runTest(t, "TestRaceInCleanup") - - // There should be one race report, for the parent test only. - cReport := bytes.Count(out, []byte("race detected during execution of test")) - wantReport := 0 - if race.Enabled { - wantReport = 1 - } - if cReport != wantReport { - t.Errorf("got %d race reports, want %d", cReport, wantReport) - } - - // Only the parent test should be marked as failed. - // (The subtest does not race, and should pass.) - cFail := bytes.Count(out, []byte("--- FAIL:")) - wantFail := 0 - if race.Enabled { - wantFail = 1 - } - if cFail != wantFail { - t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport) - } -} - -func TestDeepSubtestRace(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - t.Run("sub", func(t *testing.T) { - t.Run("subsub", func(t *testing.T) { - t.Run("subsubsub", func(t *testing.T) { - doRace() - }) - }) - doRace() - }) - return - } - - out := runTest(t, "TestDeepSubtestRace") - - c := bytes.Count(out, []byte("race detected during execution of test")) - want := 0 - // There should be two race reports. - if race.Enabled { - want = 2 - } - if c != want { - t.Errorf("got %d race reports, want %d", c, want) - } -} - -func TestRaceDuringParallelFailsAllSubtests(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - var ready sync.WaitGroup - ready.Add(2) - done := make(chan struct{}) - go func() { - ready.Wait() - doRace() // This race happens while both subtests are running. - close(done) - }() - - t.Run("sub", func(t *testing.T) { - t.Run("subsub1", func(t *testing.T) { - t.Parallel() - ready.Done() - <-done - }) - t.Run("subsub2", func(t *testing.T) { - t.Parallel() - ready.Done() - <-done - }) - }) - - return - } - - out := runTest(t, "TestRaceDuringParallelFailsAllSubtests") - - c := bytes.Count(out, []byte("race detected during execution of test")) - want := 0 - // Each subtest should report the race independently. - if race.Enabled { - want = 2 - } - if c != want { - t.Errorf("got %d race reports, want %d", c, want) - } -} - -func TestRaceBeforeParallel(t *testing.T) { - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - t.Run("sub", func(t *testing.T) { - doRace() - t.Parallel() - }) - return - } - - out := runTest(t, "TestRaceBeforeParallel") - - c := bytes.Count(out, []byte("race detected during execution of test")) - want := 0 - // We should see one race detector report. - if race.Enabled { - want = 1 - } - if c != want { - t.Errorf("got %d race reports, want %d", c, want) - } -} - -func TestRaceBeforeTests(t *testing.T) { - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^$") - cmd = testenv.CleanCmdEnv(cmd) - cmd.Env = append(cmd.Env, "GO_WANT_RACE_BEFORE_TESTS=1") - out, _ := cmd.CombinedOutput() - t.Logf("%s", out) - - c := bytes.Count(out, []byte("race detected outside of test execution")) - - want := 0 - if race.Enabled { - want = 1 - } - if c != want { - t.Errorf("got %d race reports; want %d", c, want) - } -} - -func TestBenchmarkRace(t *testing.T) { - out := runTest(t, "BenchmarkRacy") - c := bytes.Count(out, []byte("race detected during execution of test")) - - want := 0 - // We should see one race detector report. - if race.Enabled { - want = 1 - } - if c != want { - t.Errorf("got %d race reports; want %d", c, want) - } -} - -func TestBenchmarkRaceBLoop(t *testing.T) { - out := runTest(t, "BenchmarkBLoopRacy") - c := bytes.Count(out, []byte("race detected during execution of test")) - - want := 0 - // We should see one race detector report. - if race.Enabled { - want = 1 - } - if c != want { - t.Errorf("got %d race reports; want %d", c, want) - } -} - -func BenchmarkRacy(b *testing.B) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - b.Skipf("skipping intentionally-racy benchmark") - } - for i := 0; i < b.N; i++ { - doRace() - } -} - -func BenchmarkBLoopRacy(b *testing.B) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - b.Skipf("skipping intentionally-racy benchmark") - } - for b.Loop() { - doRace() - } -} - -func TestBenchmarkSubRace(t *testing.T) { - out := runTest(t, "BenchmarkSubRacy") - c := bytes.Count(out, []byte("race detected during execution of test")) - - want := 0 - // We should see 3 race detector reports: - // one in the sub-bencmark, one in the parent afterward, - // and one in b.Loop. - if race.Enabled { - want = 3 - } - if c != want { - t.Errorf("got %d race reports; want %d", c, want) - } -} - -func BenchmarkSubRacy(b *testing.B) { - if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { - b.Skipf("skipping intentionally-racy benchmark") - } - - b.Run("non-racy", func(b *testing.B) { - tot := 0 - for i := 0; i < b.N; i++ { - tot++ - } - _ = tot - }) - - b.Run("racy", func(b *testing.B) { - for i := 0; i < b.N; i++ { - doRace() - } - }) - - b.Run("racy-bLoop", func(b *testing.B) { - for b.Loop() { - doRace() - } - }) - - doRace() // should be reported separately -} - -func TestRunningTests(t *testing.T) { - t.Parallel() - - // Regression test for https://go.dev/issue/64404: - // on timeout, the "running tests" message should not include - // tests that are waiting on parked subtests. - - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - for i := 0; i < 2; i++ { - t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) { - t.Parallel() - for j := 0; j < 2; j++ { - t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) { - t.Parallel() - for { - time.Sleep(1 * time.Millisecond) - } - }) - } - }) - } - } - - timeout := 10 * time.Millisecond - for { - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String(), "-test.parallel=4") - cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1") - out, err := cmd.CombinedOutput() - t.Logf("%v:\n%s", cmd, out) - if _, ok := err.(*exec.ExitError); !ok { - t.Fatal(err) - } - - // Because the outer subtests (and TestRunningTests itself) are marked as - // parallel, their test functions return (and are no longer “running”) - // before the inner subtests are released to run and hang. - // Only those inner subtests should be reported as running. - want := []string{ - "TestRunningTests/outer0/inner0", - "TestRunningTests/outer0/inner1", - "TestRunningTests/outer1/inner0", - "TestRunningTests/outer1/inner1", - } - - got, ok := parseRunningTests(out) - if slices.Equal(got, want) { - break - } - if ok { - t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n")) - } else { - t.Logf("no running tests found") - } - t.Logf("retrying with longer timeout") - timeout *= 2 - } -} - -func TestRunningTestsInCleanup(t *testing.T) { - t.Parallel() - - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - for i := 0; i < 2; i++ { - t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) { - // Not parallel: we expect to see only one outer test, - // stuck in cleanup after its subtest finishes. - - t.Cleanup(func() { - for { - time.Sleep(1 * time.Millisecond) - } - }) - - for j := 0; j < 2; j++ { - t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) { - t.Parallel() - }) - } - }) - } - } - - timeout := 10 * time.Millisecond - for { - cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String()) - cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1") - out, err := cmd.CombinedOutput() - t.Logf("%v:\n%s", cmd, out) - if _, ok := err.(*exec.ExitError); !ok { - t.Fatal(err) - } - - // TestRunningTestsInCleanup is blocked in the call to t.Run, - // but its test function has not yet returned so it should still - // be considered to be running. - // outer1 hasn't even started yet, so only outer0 and the top-level - // test function should be reported as running. - want := []string{ - "TestRunningTestsInCleanup", - "TestRunningTestsInCleanup/outer0", - } - - got, ok := parseRunningTests(out) - if slices.Equal(got, want) { - break - } - if ok { - t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n")) - } else { - t.Logf("no running tests found") - } - t.Logf("retrying with longer timeout") - timeout *= 2 - } -} - -func parseRunningTests(out []byte) (runningTests []string, ok bool) { - inRunningTests := false - for line := range strings.SplitSeq(string(out), "\n") { - if inRunningTests { - // Package testing adds one tab, the panic printer adds another. - if trimmed, ok := strings.CutPrefix(line, "\t\t"); ok { - if name, _, ok := strings.Cut(trimmed, " "); ok { - runningTests = append(runningTests, name) - continue - } - } - - // This line is not the name of a running test. - return runningTests, true - } - - if strings.TrimSpace(line) == "running tests:" { - inRunningTests = true - } - } - - return nil, false -} - -func TestConcurrentRun(t *testing.T) { - // Regression test for https://go.dev/issue/64402: - // this deadlocked after https://go.dev/cl/506755. - - block := make(chan struct{}) - var ready, done sync.WaitGroup - for i := 0; i < 2; i++ { - ready.Add(1) - done.Add(1) - go t.Run("", func(*testing.T) { - ready.Done() - <-block - done.Done() - }) - } - ready.Wait() - close(block) - done.Wait() -} - -func TestParentRun(t1 *testing.T) { - // Regression test for https://go.dev/issue/64402: - // this deadlocked after https://go.dev/cl/506755. - - t1.Run("outer", func(t2 *testing.T) { - t2.Log("Hello outer!") - t1.Run("not_inner", func(t3 *testing.T) { // Note: this is t1.Run, not t2.Run. - t3.Log("Hello inner!") - }) - }) -} - -func TestContext(t *testing.T) { - ctx := t.Context() - if err := ctx.Err(); err != nil { - t.Fatalf("expected non-canceled context, got %v", err) - } - - var innerCtx context.Context - t.Run("inner", func(t *testing.T) { - innerCtx = t.Context() - if err := innerCtx.Err(); err != nil { - t.Fatalf("expected inner test to not inherit canceled context, got %v", err) - } - }) - t.Run("inner2", func(t *testing.T) { - if !errors.Is(innerCtx.Err(), context.Canceled) { - t.Fatal("expected context of sibling test to be canceled after its test function finished") - } - }) - - t.Cleanup(func() { - if !errors.Is(ctx.Err(), context.Canceled) { - t.Fatal("expected context canceled before cleanup") - } - }) -} - -// TestAttrExample is used by TestAttrSet, -// and also serves as a convenient test to run that sets an attribute. -func TestAttrExample(t *testing.T) { - t.Attr("key", "value") -} - -func TestAttrSet(t *testing.T) { - out := string(runTest(t, "TestAttrExample")) - - want := "=== ATTR TestAttrExample key value\n" - if !strings.Contains(out, want) { - t.Errorf("expected output containing %q, got:\n%q", want, out) - } -} - -func TestAttrInvalid(t *testing.T) { - tests := []struct { - key string - value string - }{ - {"k ey", "value"}, - {"k\tey", "value"}, - {"k\rey", "value"}, - {"k\ney", "value"}, - {"key", "val\rue"}, - {"key", "val\nue"}, - } - - if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { - for i, test := range tests { - t.Run(fmt.Sprint(i), func(t *testing.T) { - t.Attr(test.key, test.value) - }) - } - return - } - - out := string(runTest(t, "TestAttrInvalid")) - - for i := range tests { - want := fmt.Sprintf("--- FAIL: TestAttrInvalid/%v ", i) - if !strings.Contains(out, want) { - t.Errorf("expected output containing %q, got:\n%q", want, out) - } - } -} - -func TestBenchmarkBLoopIterationCorrect(t *testing.T) { - out := runTest(t, "BenchmarkBLoopPrint") - c := bytes.Count(out, []byte("Printing from BenchmarkBLoopPrint")) - - want := 2 - if c != want { - t.Errorf("got %d loop iterations; want %d", c, want) - } - - // b.Loop() will only rampup once. - c = bytes.Count(out, []byte("Ramping up from BenchmarkBLoopPrint")) - want = 1 - if c != want { - t.Errorf("got %d loop rampup; want %d", c, want) - } - - re := regexp.MustCompile(`BenchmarkBLoopPrint(-[0-9]+)?\s+2\s+[0-9]+\s+ns/op`) - if !re.Match(out) { - t.Error("missing benchmark output") - } -} - -func TestBenchmarkBNIterationCorrect(t *testing.T) { - out := runTest(t, "BenchmarkBNPrint") - c := bytes.Count(out, []byte("Printing from BenchmarkBNPrint")) - - // runTest sets benchtime=2x, with semantics specified in #32051 it should - // run 3 times. - want := 3 - if c != want { - t.Errorf("got %d loop iterations; want %d", c, want) - } - - // b.N style fixed iteration loop will rampup twice: - // One in run1(), the other in launch - c = bytes.Count(out, []byte("Ramping up from BenchmarkBNPrint")) - want = 2 - if c != want { - t.Errorf("got %d loop rampup; want %d", c, want) - } -} - -func BenchmarkBLoopPrint(b *testing.B) { - b.Logf("Ramping up from BenchmarkBLoopPrint") - for b.Loop() { - b.Logf("Printing from BenchmarkBLoopPrint") - } -} - -func BenchmarkBNPrint(b *testing.B) { - b.Logf("Ramping up from BenchmarkBNPrint") - for i := 0; i < b.N; i++ { - b.Logf("Printing from BenchmarkBNPrint") - } -} diff --git a/testing/testing/testing_windows.go b/testing/testing/testing_windows.go deleted file mode 100644 index 731b1da0..00000000 --- a/testing/testing/testing_windows.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2021 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 windows - -package testing - -import ( - "errors" - "github.com/CodSpeedHQ/codspeed-go/testing/internal/syscall/windows" - "math/bits" - "syscall" - "time" -) - -// isWindowsRetryable reports whether err is a Windows error code -// that may be fixed by retrying a failed filesystem operation. -func isWindowsRetryable(err error) bool { - for { - unwrapped := errors.Unwrap(err) - if unwrapped == nil { - break - } - err = unwrapped - } - if err == syscall.ERROR_ACCESS_DENIED { - return true // Observed in https://go.dev/issue/50051. - } - if err == windows.ERROR_SHARING_VIOLATION { - return true // Observed in https://go.dev/issue/51442. - } - return false -} - -// highPrecisionTime represents a single point in time with query performance counter. -// time.Time on Windows has low system granularity, which is not suitable for -// measuring short time intervals. -// -// TODO: If Windows runtime implements high resolution timing then highPrecisionTime -// can be removed. -type highPrecisionTime struct { - now int64 -} - -// highPrecisionTimeNow returns high precision time for benchmarking. -func highPrecisionTimeNow() highPrecisionTime { - var t highPrecisionTime - // This should always succeed for Windows XP and above. - t.now = windows.QueryPerformanceCounter() - return t -} - -func (a highPrecisionTime) sub(b highPrecisionTime) time.Duration { - delta := a.now - b.now - - if queryPerformanceFrequency == 0 { - queryPerformanceFrequency = windows.QueryPerformanceFrequency() - } - hi, lo := bits.Mul64(uint64(delta), uint64(time.Second)/uint64(time.Nanosecond)) - quo, _ := bits.Div64(hi, lo, uint64(queryPerformanceFrequency)) - return time.Duration(quo) -} - -var queryPerformanceFrequency int64 - -// highPrecisionTimeSince returns duration since a. -func highPrecisionTimeSince(a highPrecisionTime) time.Duration { - return highPrecisionTimeNow().sub(a) -} diff --git a/testing/testing/testing_windows_test.go b/testing/testing/testing_windows_test.go deleted file mode 100644 index e75232de..00000000 --- a/testing/testing/testing_windows_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2024 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 ( - "testing" - "time" -) - -var sink time.Time -var sinkHPT testing.HighPrecisionTime - -func BenchmarkTimeNow(b *testing.B) { - for i := 0; i < b.N; i++ { - sink = time.Now() - } -} - -func BenchmarkHighPrecisionTimeNow(b *testing.B) { - for i := 0; i < b.N; i++ { - sinkHPT = testing.HighPrecisionTimeNow() - } -} From ee48eb7cfd0bdab4b83068b1519494253d76e21e Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:00:07 +0100 Subject: [PATCH 04/13] feat(go-runner): rewrite crate to use overlay files --- Cargo.lock | 1568 ++++++++++++++--- go-runner/Cargo.toml | 13 +- go-runner/benches/go_runner.rs | 28 - go-runner/docs/test-execution-strategy.md | 152 -- go-runner/overlay/benchmark.go | 1184 +++++++++++++ go-runner/overlay/codspeed.go | 183 ++ go-runner/overlay/instrument-hooks.go | 97 + go-runner/src/builder/discovery.rs | 407 ----- go-runner/src/builder/mod.rs | 199 --- go-runner/src/builder/patcher.rs | 494 ------ ...discovery__tests__discover_benchmarks.snap | 1080 ------------ ...ery__tests__discover_benchmarks@caddy.snap | 109 -- ...ests__discover_benchmarks@cli-runtime.snap | 83 - ...benchmarks@example-with-dot-go-folder.snap | 32 - ...scover_benchmarks@example-with-helper.snap | 19 - ...discover_benchmarks@example-with-main.snap | 19 - ..._benchmarks@example-with-test-package.snap | 74 - ...y__tests__discover_benchmarks@example.snap | 348 ---- ...ery__tests__discover_benchmarks@fuego.snap | 99 -- ...overy__tests__discover_benchmarks@fzf.snap | 35 - ...discover_benchmarks@golang-benchmarks.snap | 798 --------- ...very__tests__discover_benchmarks@hugo.snap | 1416 --------------- ...scover_benchmarks@hugo__common__htime.snap | 60 - ...s__discover_benchmarks@hugo__identity.snap | 64 - ..._discover_benchmarks@opentelemetry-go.snap | 247 --- ...y__tests__discover_benchmarks@quic-go.snap | 381 ---- ...overy__tests__discover_benchmarks@zap.snap | 372 ---- ...y__tests__discover_benchmarks@zerolog.snap | 233 --- ...atcher__tests__already_patched_import.snap | 11 - ...atcher__tests__import_at_end_of_block.snap | 11 - ..._tests__import_testing_and_slogassert.snap | 10 - ..._patcher__tests__import_with_comments.snap | 11 - ...__tests__import_with_extra_whitespace.snap | 13 - ...er__tests__import_with_testing_string.snap | 11 - ..._patcher__tests__many_testing_imports.snap | 13 - ...__patcher__tests__mixed_import_styles.snap | 12 - ...__tests__multiline_import_replacement.snap | 15 - ...er__tests__multiline_import_with_tabs.snap | 11 - ..._multiline_import_with_testing_string.snap | 13 - ...builder__patcher__tests__package_main.snap | 15 - ...her__tests__single_import_replacement.snap | 11 - go-runner/src/builder/template.go | 85 - go-runner/src/builder/templater.rs | 291 --- go-runner/src/integration_tests.rs | 9 +- go-runner/src/lib.rs | 66 +- go-runner/src/main.rs | 2 +- go-runner/src/runner.rs | 56 - go-runner/src/runner/mod.rs | 71 + .../src/runner/overlay/instrument_hooks.rs | 37 + go-runner/src/runner/overlay/mod.rs | 88 + ...s_snapshots@example-with-test-package.snap | 34 +- ...n_tests__assert_results_snapshots@zap.snap | 118 +- ...sts__assert_results_snapshots@zerolog.snap | 14 +- go-runner/src/utils.rs | 96 - go-runner/tests/error_file.rs | 25 +- go-runner/tests/pkg_arg.rs | 6 +- go-runner/tests/utils.rs | 53 +- go.mod | 10 - go.sum | 10 - 59 files changed, 3066 insertions(+), 7956 deletions(-) delete mode 100644 go-runner/docs/test-execution-strategy.md create mode 100644 go-runner/overlay/benchmark.go create mode 100644 go-runner/overlay/codspeed.go create mode 100644 go-runner/overlay/instrument-hooks.go delete mode 100644 go-runner/src/builder/discovery.rs delete mode 100644 go-runner/src/builder/mod.rs delete mode 100644 go-runner/src/builder/patcher.rs delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@caddy.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@cli-runtime.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-dot-go-folder.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-helper.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-main.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-test-package.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fuego.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fzf.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@golang-benchmarks.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__common__htime.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__identity.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@opentelemetry-go.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@quic-go.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zap.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zerolog.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__already_patched_import.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_at_end_of_block.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_testing_and_slogassert.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_comments.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_extra_whitespace.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_testing_string.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__many_testing_imports.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__mixed_import_styles.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_replacement.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_tabs.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_testing_string.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__package_main.snap delete mode 100644 go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__single_import_replacement.snap delete mode 100644 go-runner/src/builder/template.go delete mode 100644 go-runner/src/builder/templater.rs delete mode 100644 go-runner/src/runner.rs create mode 100644 go-runner/src/runner/mod.rs create mode 100644 go-runner/src/runner/overlay/instrument_hooks.rs create mode 100644 go-runner/src/runner/overlay/mod.rs delete mode 100644 go-runner/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index e2ccccad..f7690ea5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.3" @@ -76,12 +82,46 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "2.9.3" @@ -97,16 +137,36 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bytes" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" + [[package]] name = "cc" -version = "1.2.45" +version = "1.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35900b6c8d709fb1d854671ae27aeaa9eec2f8b01b364e1619a40da3e6fe2afe" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.3" @@ -126,7 +186,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57" dependencies = [ "clap_builder", - "clap_derive", ] [[package]] @@ -135,31 +194,26 @@ version = "4.5.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41" dependencies = [ - "anstream", "anstyle", "clap_lex", - "strsim", "terminal_size", ] -[[package]] -name = "clap_derive" -version = "4.5.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "clap_lex" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "codspeed" version = "4.1.0" @@ -225,13 +279,10 @@ name = "codspeed-go-runner" version = "0.6.2" dependencies = [ "anyhow", - "clap", "codspeed-divan-compat", - "dircpy", "env_logger", + "flate2", "glob", - "gosyn", - "handlebars", "insta", "itertools", "log", @@ -240,14 +291,14 @@ dependencies = [ "rand", "rayon", "regex", + "reqwest", "rstest", - "semver", "serde", "serde_json", "statrs", + "tar", "tempfile", "test-log", - "thiserror 2.0.16", ] [[package]] @@ -266,6 +317,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "condtype" version = "1.3.0" @@ -285,34 +346,47 @@ dependencies = [ ] [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ + "core-foundation-sys", "libc", ] [[package]] -name = "crossbeam" -version = "0.8.4" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", ] [[package]] -name = "crossbeam-channel" -version = "0.5.15" +name = "crc32fast" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ - "crossbeam-utils", + "cfg-if", ] [[package]] @@ -334,15 +408,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -359,72 +424,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn", -] - [[package]] name = "digest" version = "0.10.7" @@ -436,14 +435,14 @@ dependencies = [ ] [[package]] -name = "dircpy" -version = "0.3.19" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88521b0517f5f9d51d11925d8ab4523497dcf947073fa3231a311b63941131c" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "jwalk", - "log", - "walkdir", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -457,6 +456,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "either" version = "1.15.0" @@ -469,6 +474,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_filter" version = "0.1.3" @@ -514,11 +528,33 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + [[package]] name = "find-msvc-tools" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "flate2" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +dependencies = [ + "crc32fast", + "miniz_oxide", +] [[package]] name = "fnv" @@ -526,12 +562,43 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + [[package]] name = "futures-macro" version = "0.3.31" @@ -543,6 +610,12 @@ dependencies = [ "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + [[package]] name = "futures-task" version = "0.3.31" @@ -562,8 +635,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -586,8 +662,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -597,9 +675,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -609,109 +689,303 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "gosyn" -version = "0.2.9" +name = "h2" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb37859fda6792e95231aef1c5838f4043ec0ee352d8313421e311c606df612" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ - "anyhow", - "strum", - "thiserror 1.0.69", - "unic-ucd-category", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "handlebars" -version = "6.3.2" +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" + +[[package]] +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759e2d5aea3287cb1190c8ec394f42866cb5bf74fcbf213f354e3c856ea26098" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "derive_builder", - "log", - "num-order", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror 2.0.16", + "bytes", + "itoa", ] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] [[package]] -name = "heck" -version = "0.4.1" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] [[package]] -name = "heck" -version = "0.5.0" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "ident_case" -version = "1.0.1" +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] [[package]] -name = "indexmap" -version = "2.11.0" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "equivalent", - "hashbrown", + "http", + "hyper", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", ] [[package]] -name = "insta" -version = "1.43.1" +name = "hyper-util" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ - "console", - "once_cell", - "pest", - "pest_derive", - "serde", - "similar", + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "itertools" -version = "0.14.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "either", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "itoa" -version = "1.0.15" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] [[package]] -name = "jiff" -version = "0.2.15" +name = "icu_normalizer_data" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" -dependencies = [ - "jiff-static", +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "insta" +version = "1.43.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371" +dependencies = [ + "console", + "once_cell", + "pest", + "pest_derive", + "serde", + "similar", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", "log", "portable-atomic", "portable-atomic-util", @@ -730,13 +1004,45 @@ dependencies = [ ] [[package]] -name = "jwalk" -version = "0.8.1" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ - "crossbeam", - "rayon", + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +dependencies = [ + "once_cell", + "wasm-bindgen", ] [[package]] @@ -761,18 +1067,41 @@ dependencies = [ "libc", ] +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + [[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "matchers" version = "0.2.0" @@ -782,12 +1111,6 @@ dependencies = [ "regex-automata", ] -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" version = "2.7.5" @@ -803,6 +1126,33 @@ dependencies = [ "libmimalloc-sys", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + [[package]] name = "nix" version = "0.30.1" @@ -824,21 +1174,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "num-modular" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" - -[[package]] -name = "num-order" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" -dependencies = [ - "num-modular", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -860,6 +1195,18 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "pest" version = "2.8.1" @@ -931,6 +1278,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -958,6 +1314,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.16", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "aws-lc-rs", + "bytes", + "getrandom 0.3.3", + "lru-slab", + "rand", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.16", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.60.2", +] + [[package]] name = "quote" version = "1.0.40" @@ -1022,6 +1434,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.12.2" @@ -1063,6 +1484,60 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" +[[package]] +name = "reqwest" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rstest" version = "0.26.1" @@ -1092,6 +1567,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.4.1" @@ -1114,6 +1595,81 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "rustls" +version = "0.23.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -1136,8 +1692,40 @@ dependencies = [ ] [[package]] -name = "semver" -version = "1.0.27" +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" @@ -1199,6 +1787,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + [[package]] name = "similar" version = "2.7.0" @@ -1211,6 +1805,28 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "statrs" version = "0.18.0" @@ -1222,42 +1838,72 @@ dependencies = [ ] [[package]] -name = "strsim" -version = "0.11.1" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] -name = "strum" -version = "0.25.0" +name = "syn" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ - "strum_macros", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] -name = "strum_macros" -version = "0.25.3" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "heck 0.4.1", "proc-macro2", "quote", - "rustversion", "syn", ] [[package]] -name = "syn" -version = "2.0.106" +name = "system-configuration" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "bitflags", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", ] [[package]] @@ -1354,6 +2000,68 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -1371,6 +2079,51 @@ dependencies = [ "winnow", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.41" @@ -1419,6 +2172,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typenum" version = "1.18.0" @@ -1432,52 +2191,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" +name = "unicode-ident" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] -name = "unic-ucd-category" +name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8d4591f5fcfe1bd4453baaf803c40e1b1e69ff8455c47620440b46efef91c0" -dependencies = [ - "matches", - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "unic-ucd-version" -version = "0.9.0" +name = "url" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ - "unic-common", + "form_urlencoded", + "idna", + "percent-encoding", + "serde", ] [[package]] -name = "unicode-ident" -version = "1.0.18" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" @@ -1507,6 +2248,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1522,13 +2272,100 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi-util" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1537,6 +2374,50 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1564,6 +2445,30 @@ dependencies = [ "windows-targets 0.53.3", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1586,7 +2491,7 @@ version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -1597,6 +2502,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -1609,6 +2520,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -1621,6 +2538,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1645,6 +2568,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -1657,6 +2586,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -1669,6 +2604,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -1681,6 +2622,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1711,6 +2658,45 @@ dependencies = [ "bitflags", ] +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.27" @@ -1730,3 +2716,63 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/go-runner/Cargo.toml b/go-runner/Cargo.toml index c1558db8..415a985e 100644 --- a/go-runner/Cargo.toml +++ b/go-runner/Cargo.toml @@ -7,24 +7,21 @@ publish = false [dependencies] anyhow = "1.0" -clap = { version = "4.5", features = ["derive"] } env_logger = "0.11" glob = "0.3" -gosyn = "0.2" -handlebars = "6.3" -itertools = "0.14" log = "0.4" regex = "1.11" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" statrs = { version = "0.18", default-features = false } -thiserror = "2.0" tempfile = "3.14" -semver = "1.0.27" -dircpy = "0.3.19" -rayon = "1" once_cell = "1.21.3" mimalloc = "0.1.48" +flate2 = "1.1.5" +tar = "0.4.44" +reqwest = { version = "0.13.1", features = ["blocking"] } +rayon = "1.11.0" +itertools = "0.14.0" [dev-dependencies] divan = { version = "4.1.0", package = "codspeed-divan-compat" } diff --git a/go-runner/benches/go_runner.rs b/go-runner/benches/go_runner.rs index caa010ba..e273d94b 100644 --- a/go-runner/benches/go_runner.rs +++ b/go-runner/benches/go_runner.rs @@ -2,34 +2,6 @@ use codspeed_go_runner::results::raw_result::RawResult; use std::time::Duration; use tempfile::TempDir; -#[divan::bench(max_time = std::time::Duration::from_secs(5))] -fn bench_go_runner(bencher: divan::Bencher) { - use std::path::PathBuf; - use tempfile::TempDir; - - let project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/projects/example"); - - bencher - .with_inputs(|| { - let temp_dir = TempDir::new().unwrap(); - let profile_dir = temp_dir.path().join("profile"); - let cli = codspeed_go_runner::cli::Cli { - packages: vec!["./...".into()], - dry_run: true, - ..Default::default() - }; - - (profile_dir, cli) - }) - .bench_refs(|(profile_dir, cli)| { - if let Err(error) = - codspeed_go_runner::run_benchmarks(profile_dir, project_dir.as_path(), cli) - { - panic!("Benchmarks couldn't run: {error}"); - } - }); -} - const TIME_ENTRIES: [usize; 5] = [100_000, 500_000, 1_000_000, 5_000_000, 10_000_000]; const FILE_COUNT: [usize; 3] = [5, 10, 25]; diff --git a/go-runner/docs/test-execution-strategy.md b/go-runner/docs/test-execution-strategy.md deleted file mode 100644 index 48692c6c..00000000 --- a/go-runner/docs/test-execution-strategy.md +++ /dev/null @@ -1,152 +0,0 @@ -# Test Execution Strategy - -This document explains how go-runner executes benchmarks for both internal and external test packages. - -## Overview - -Go supports two testing patterns: -- **Internal tests** (`package foo`) - Same package as the code being tested -- **External tests** (`package foo_test`) - Separate package for black-box testing - -Each pattern requires a different execution strategy because of Go's package import rules. - -## Internal Test Execution - -**Example:** -```go -// fib.go -package fib - -func Fibonacci(n int) int { ... } - -// fib_test.go -package fib // ← Same package - -import "testing" - -func BenchmarkFibonacci(b *testing.B) { - Fibonacci(10) // ← Direct call (same package) -} -``` - -**Strategy:** - -1. **Rename test files**: `fib_test.go` → `fib_codspeed.go` - - Why: `go build` only compiles `*_test.go` files with `go test`, not `go build` - -2. **Patch imports**: Replace `import "testing"` with CodSpeed compat package - - Done by: `patcher::patch_imports()` in `src/builder/patcher.rs` - -3. **Create codspeed sub-package**: `codspeed/runner.go` - - The sub-package can import the parent package - - Template: `src/builder/template.go` with Handlebars - -4. **Import and reference benchmarks** in runner: - ```go - import benchmarkfib_12345 "example.com/pkg/fib" - - var benchmarks = []InternalBenchmark{ - {"BenchmarkFibonacci", benchmarkfib_12345.BenchmarkFibonacci}, - } - ``` - -5. **Build and run**: `go build -tags=codspeed ./codspeed` - - Executed by: `builder::build_binary()` in `src/builder/mod.rs` - -**Key files:** -- `src/builder/templater.rs` - Orchestrates the process (line 105-121: internal test handling) -- `src/builder/template.go` - Handlebars template (line 12-14: conditional imports) - -## External Test Execution - -**Example:** -```go -// fib.go -package fib - -func Fibonacci(n int) int { ... } - -// fib_integration_test.go -package fib_test // ← Different package (_test suffix) - -import "testing" -import "example.com/pkg/fib" // ← Must import the package - -func BenchmarkFibonacci(b *testing.B) { - fib.Fibonacci(10) // ← Qualified call (external package) -} -``` - -**Strategy:** - -1. **Move test files to codspeed/**: `fib_integration_test.go` → `codspeed/fib_integration_codspeed.go` - - Why: Avoids package conflicts (can't have `package fib` and `package fib_test` in same directory) - -2. **Rename package**: `package fib_test` → `package main` - - Why: Runner is `package main`, all files in codspeed/ must use same package - - Done by: `patcher::patch_package_for_source()` in `src/builder/patcher.rs` (line 168-193) - -3. **Patch imports**: Replace testing imports with CodSpeed compat packages - -4. **Create runner in same package**: `codspeed/runner.go` as `package main` - - Template: Same `template.go` but with different conditionals - -5. **Direct benchmark references** (no import needed): - ```go - // NO import needed - benchmarks are in the same package (main) - - var benchmarks = []InternalBenchmark{ - {"BenchmarkFibonacci", BenchmarkFibonacci}, // ← Direct reference - } - ``` - -6. **Build entire directory**: `go build -tags=codspeed ./codspeed` - - Compiles all `.go` files in the directory together - -**Key files:** -- `src/builder/templater.rs` - Orchestrates the process (line 88-104: external test handling) -- `src/builder/template.go` - Template conditionals (line 12-14: skip imports, line 78-79: direct vs qualified names) - -## Special Case: Package Main - -When benchmarks exist in `package main`: - -**Problem**: Go doesn't allow importing `package main` - -**Solution**: Rename all `.go` files in the package to `package main_compat` -- Done by: `patcher::patch_all_packages_in_dir()` in `src/builder/patcher.rs` (line 138-164) -- Triggered in: `src/builder/templater.rs` (line 79-87) - -This makes the package importable by the runner. - -## Template Conditionals - -The `template.go` file uses Handlebars to generate different code based on test type: - -```go -// Import only for internal tests -{{#each benchmarks}} - {{#unless is_external}}{{import_alias}} "{{module_path}}"{{/unless}} -{{/each}} - -// Reference: qualified (internal) vs direct (external) -{{#each benchmarks}} - {"{{name}}", - {{#if is_external}}{{name}}{{else}}{{qualified_name}}{{/if}}}, -{{/each}} -``` - -The `is_external` flag is set during discovery in `src/builder/discovery.rs`. - -## Build Process - -All paths converge to a single build command: - -```rust -// src/builder/mod.rs:build_binary() -go build -tags=codspeed -o ./ -``` - -The key difference is what files are in the `codspeed/` directory: -- **Internal tests**: Only `runner.go` -- **External tests**: `runner.go` + renamed test files (`*_codspeed.go`) diff --git a/go-runner/overlay/benchmark.go b/go-runner/overlay/benchmark.go new file mode 100644 index 00000000..16e1aebd --- /dev/null +++ b/go-runner/overlay/benchmark.go @@ -0,0 +1,1184 @@ +// Copyright 2009 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 + +import ( + "context" + "flag" + "fmt" + "internal/sysinfo" + "io" + "math" + "os" + "runtime" + "slices" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unicode" +) + +func initBenchmarkFlags() { + matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`") + benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks") + flag.Var(&benchTime, "test.benchtime", "run each benchmark for duration `d` or N times if `d` is of the form Nx") +} + +var ( + matchBenchmarks *string + benchmarkMemory *bool + + benchTime = durationOrCountFlag{d: 1 * time.Second} // changed during test of testing package +) + +type durationOrCountFlag struct { + d time.Duration + n int + allowZero bool +} + +func (f *durationOrCountFlag) String() string { + if f.n > 0 { + return fmt.Sprintf("%dx", f.n) + } + return f.d.String() +} + +func (f *durationOrCountFlag) Set(s string) error { + if strings.HasSuffix(s, "x") { + n, err := strconv.ParseInt(s[:len(s)-1], 10, 0) + if err != nil || n < 0 || (!f.allowZero && n == 0) { + return fmt.Errorf("invalid count") + } + *f = durationOrCountFlag{n: int(n)} + return nil + } + d, err := time.ParseDuration(s) + if err != nil || d < 0 || (!f.allowZero && d == 0) { + return fmt.Errorf("invalid duration") + } + *f = durationOrCountFlag{d: d} + return nil +} + +// Global lock to ensure only one benchmark runs at a time. +var benchmarkLock sync.Mutex + +// Used for every benchmark for measuring memory. +var memStats runtime.MemStats + +// InternalBenchmark is an internal type but exported because it is cross-package; +// it is part of the implementation of the "go test" command. +type InternalBenchmark struct { + Name string + F func(b *B) +} + +type codspeed struct { + instrument_hooks *InstrumentHooks + + codspeedTimePerRoundNs []time.Duration + codspeedItersPerRound []int64 + + startTimestamp uint64 + startTimestamps []uint64 + stopTimestamps []uint64 + + // Indicates whether a measurement has been saved already. This aims to prevent saving measurements + // twice, because `b.Loop()` saves them internally as well but is also called from runN + savedMeasurement bool +} + +// B is a type passed to [Benchmark] functions to manage benchmark +// timing and control the number of iterations. +// +// A benchmark ends when its Benchmark function returns or calls any of the methods +// [B.FailNow], [B.Fatal], [B.Fatalf], [B.SkipNow], [B.Skip], or [B.Skipf]. +// Those methods must be called only from the goroutine running the Benchmark function. +// The other reporting methods, such as the variations of [B.Log] and [B.Error], +// may be called simultaneously from multiple goroutines. +// +// Like in tests, benchmark logs are accumulated during execution +// and dumped to standard output when done. Unlike in tests, benchmark logs +// are always printed, so as not to hide output whose existence may be +// affecting benchmark results. +type B struct { + common + codspeed + importPath string // import path of the package containing the benchmark + bstate *benchState + N int + previousN int // number of iterations in the previous run + previousDuration time.Duration // total duration of the previous run + benchFunc func(b *B) + benchTime durationOrCountFlag + bytes int64 + missingBytes bool // one of the subbenchmarks does not have bytes set. + timerOn bool + showAllocResult bool + result BenchmarkResult + parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines + // The initial states of memStats.Mallocs and memStats.TotalAlloc. + startAllocs uint64 + startBytes uint64 + // The net total of this test after being run. + netAllocs uint64 + netBytes uint64 + // Extra metrics collected by ReportMetric. + extra map[string]float64 + + // loop tracks the state of B.Loop + loop struct { + // n is the target number of iterations. It gets bumped up as we go. + // When the benchmark loop is done, we commit this to b.N so users can + // do reporting based on it, but we avoid exposing it until then. + n uint64 + // i is the current Loop iteration. It's strictly monotonically + // increasing toward n. + // + // The high bit is used to poison the Loop fast path and fall back to + // the slow path. + i uint64 + + done bool // set when B.Loop return false + } +} + +// StartTimer starts timing a test. This function is called automatically +// before a benchmark starts, but it can also be used to resume timing after +// a call to [B.StopTimer]. +func (b *B) StartTimerWithoutMarker() { + if !b.timerOn { + // runtime.ReadMemStats(&memStats) + // b.startAllocs = memStats.Mallocs + // b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() + b.timerOn = true + b.savedMeasurement = false + // b.loop.i &^= loopPoisonTimer + } +} + +func (b *B) StartTimer() { + timerOn := b.timerOn + + b.StartTimerWithoutMarker() + + if !timerOn { + b.startTimestamp = CurrentTimestamp() + } +} + +// StopTimer stops timing a test. This can be used to pause the timer +// while performing steps that you don't want to measure. +func (b *B) StopTimerWithoutMarker() { + if b.timerOn { + timeSinceStart := highPrecisionTimeSince(b.start) + b.duration += timeSinceStart + // runtime.ReadMemStats(&memStats) + // b.netAllocs += memStats.Mallocs - b.startAllocs + // b.netBytes += memStats.TotalAlloc - b.startBytes + b.timerOn = false + // If we hit B.Loop with the timer stopped, fail. + // b.loop.i |= loopPoisonTimer + } +} + +func (b *B) SaveMeasurement() { + if b.savedMeasurement { + return + } + b.savedMeasurement = true + + // WARN: This function must not be called if the timer is on, because we + // would read an incomplete b.duration value. + if b.timerOn { + panic("SaveMeasurement called with timer on") + } + + // For b.N loops: This will be called in runN which sets b.N to the number of iterations. + // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since + // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as + // the number of iterations for this round. + timeSinceStart := highPrecisionTimeSince(b.start) + + // If this gets called from b.Loop(), we have to take the duration compared to the previous StartTimer, + // if it's called from runN, we can use b.duration + duration := time.Duration(0) + if b.N == 0 { + duration = timeSinceStart + } else { + duration = b.duration + } + + b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) + b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, duration) +} + +func (b *B) StopTimer() { + endTimestamp := CurrentTimestamp() + timerOn := b.timerOn + + b.StopTimerWithoutMarker() + + if timerOn { + b.AddBenchmarkMarkers(endTimestamp) + } +} + +// ResetTimer zeroes the elapsed benchmark time and memory allocation counters +// and deletes user-reported metrics. +// It does not affect whether the timer is running. +func (b *B) ResetTimer() { + if b.extra == nil { + // Allocate the extra map before reading memory stats. + // Pre-size it to make more allocation unlikely. + b.extra = make(map[string]float64, 16) + } else { + clear(b.extra) + } + if b.timerOn { + runtime.ReadMemStats(&memStats) + b.startAllocs = memStats.Mallocs + b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() + + b.startTimestamp = CurrentTimestamp() + } + b.duration = 0 + b.netAllocs = 0 + b.netBytes = 0 + + // Clear CodSpeed timestamp data + b.codspeedItersPerRound = b.codspeedItersPerRound[:0] + b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] + b.startTimestamps = b.startTimestamps[:0] + b.stopTimestamps = b.stopTimestamps[:0] +} + +func (b *B) sendAccumulatedTimestamps() { + for i := 0; i < len(b.startTimestamps); i++ { + b.instrument_hooks.AddBenchmarkTimestamps( + b.startTimestamps[i], + b.stopTimestamps[i], + ) + } + b.startTimestamps = b.startTimestamps[:0] + b.stopTimestamps = b.stopTimestamps[:0] +} + +// SetBytes records the number of bytes processed in a single operation. +// If this is called, the benchmark will report ns/op and MB/s. +func (b *B) SetBytes(n int64) { b.bytes = n } + +// ReportAllocs enables malloc statistics for this benchmark. +// It is equivalent to setting -test.benchmem, but it only affects the +// benchmark function that calls ReportAllocs. +func (b *B) ReportAllocs() { + b.showAllocResult = true +} + +// runN runs a single benchmark for the specified number of iterations. +func (b *B) runN(n int) { + b.__codspeed_root_frame__runN(n) +} + +//go:noinline +func (b *B) __codspeed_root_frame__runN(n int) { + benchmarkLock.Lock() + defer benchmarkLock.Unlock() + ctx, cancelCtx := context.WithCancel(context.Background()) + defer func() { + b.runCleanup(normalPanic) + b.checkRaces() + }() + // Try to get a comparable environment for each run + // by clearing garbage from previous runs. + runtime.GC() + b.resetRaces() + b.N = n + b.loop.n = 0 + b.loop.i = 0 + b.loop.done = false + b.ctx = ctx + b.cancelCtx = cancelCtx + + b.parallelism = 1 + b.ResetTimer() + b.StartTimer() + b.benchFunc(b) + b.StopTimer() + b.SaveMeasurement() + b.previousN = n + b.previousDuration = b.duration + + if b.loop.n > 0 && !b.loop.done && !b.failed { + b.Error("benchmark function returned without B.Loop() == false (break or return in loop?)") + } +} + +// run1 runs the first iteration of benchFunc. It reports whether more +// iterations of this benchmarks should be run. +func (b *B) run1() bool { + if bstate := b.bstate; bstate != nil { + // Extend maxLen, if needed. + if n := len(b.name) + bstate.extLen + 1; n > bstate.maxLen { + bstate.maxLen = n + 8 // Add additional slack to avoid too many jumps in size. + } + } + go func() { + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- true + }() + + b.runN(1) + }() + <-b.signal + if b.failed { + // This case can happen with a `b.Loop()` benchmark if any of the iterations fail + ensureBenchmarkIsStopped(b) + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) + return false + } + // Only print the output if we know we are not going to proceed. + // Otherwise it is printed in processBench. + b.mu.RLock() + finished := b.finished + b.mu.RUnlock() + if b.hasSub.Load() || finished { + tag := "BENCH" + if b.skipped { + tag = "SKIP" + } + if b.chatty != nil && (len(b.output) > 0 || finished) { + b.trimOutput() + fmt.Fprintf(b.w, "%s--- %s: %s\n%s", b.chatty.prefix(), tag, b.name, b.output) + } + return false + } + return true +} + +var labelsOnce sync.Once + +// run executes the benchmark in a separate goroutine, including all of its +// subbenchmarks. b must not have subbenchmarks. +func (b *B) run() { + labelsOnce.Do(func() { + fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") + + fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) + fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { + fmt.Fprintf(b.w, "pkg: %s\n", b.importPath) + } + if cpu := sysinfo.CPUName(); cpu != "" { + fmt.Fprintf(b.w, "cpu: %s\n", cpu) + } + }) + if b.bstate != nil { + // Running go test --test.bench + b.bstate.processBench(b) // Must call doBench. + } else { + // Running func Benchmark. + b.doBench() + } +} + +func (b *B) doBench() BenchmarkResult { + go b.launch() + <-b.signal + return b.result +} + +func predictN(goalns int64, prevIters int64, prevns int64, last int64) int { + if prevns == 0 { + // Round up to dodge divide by zero. See https://go.dev/issue/70709. + prevns = 1 + } + + // Order of operations matters. + // For very fast benchmarks, prevIters ~= prevns. + // If you divide first, you get 0 or 1, + // which can hide an order of magnitude in execution time. + // So multiply first, then divide. + n := goalns * prevIters / prevns + // Run more iterations than we think we'll need (1.2x). + n += n / 5 + // Don't grow too fast in case we had timing errors previously. + n = min(n, 100*last) + // Be sure to run at least one more than last time. + n = max(n, last+1) + // Don't run more than 1e9 times. (This also keeps n in int range on 32 bit platforms.) + n = min(n, 1e9) + return int(n) +} + +// launch launches the benchmark function. It gradually increases the number +// of benchmark iterations until the benchmark runs for the requested benchtime. +// launch is run by the doBench function as a separate goroutine. +// run1 must have been called on b. +func (b *B) launch() { + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- true + }() + + // b.Loop does its own ramp-up logic so we just need to run it once. + // If b.loop.n is non zero, it means b.Loop has already run. + if b.loop.n == 0 { + // Run the benchmark for at least the specified amount of time. + if b.benchTime.n > 0 { + // We already ran a single iteration in run1. + // If -benchtime=1x was requested, use that result. + // See https://golang.org/issue/32051. + if b.benchTime.n > 1 { + b.runN(b.benchTime.n) + } + } else { + warmupD := b.benchTime.d / 10 + warmupN := int64(1) + for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { + last := n + // Predict required iterations. + goalns := warmupD.Nanoseconds() + prevIters := int64(b.N) + n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) + b.runN(int(n)) + warmupN = n + } + + // Reset the fields from the warmup run + b.ResetTimer() + + // Final run: + benchD := b.benchTime.d + benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) + + // When we have a very slow benchmark (e.g. taking 500ms), we have to: + // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) + // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds + const minRounds = 100 + var rounds int + var roundN int + if benchN < minRounds { + rounds = benchN + roundN = 1 + } else { + rounds = minRounds + roundN = benchN / int(rounds) + } + + b.codspeed.instrument_hooks.StartBenchmark() + for range rounds { + b.runN(int(roundN)) + } + b.codspeed.instrument_hooks.StopBenchmark() + b.sendAccumulatedTimestamps() + } + } + b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} +} + +// Elapsed returns the measured elapsed time of the benchmark. +// The duration reported by Elapsed matches the one measured by +// [B.StartTimer], [B.StopTimer], and [B.ResetTimer]. +func (b *B) Elapsed() time.Duration { + d := b.duration + if b.timerOn { + d += highPrecisionTimeSince(b.start) + } + return d +} + +// ReportMetric adds "n unit" to the reported benchmark results. +// If the metric is per-iteration, the caller should divide by b.N, +// and by convention units should end in "/op". +// ReportMetric overrides any previously reported value for the same unit. +// ReportMetric panics if unit is the empty string or if unit contains +// any whitespace. +// If unit is a unit normally reported by the benchmark framework itself +// (such as "allocs/op"), ReportMetric will override that metric. +// Setting "ns/op" to 0 will suppress that built-in metric. +func (b *B) ReportMetric(n float64, unit string) { + if unit == "" { + panic("metric unit must not be empty") + } + if strings.IndexFunc(unit, unicode.IsSpace) >= 0 { + panic("metric unit must not contain whitespace") + } + b.extra[unit] = n +} + +func (b *B) stopOrScaleBLoop() bool { + t := b.Elapsed() + if t >= b.benchTime.d { + // We've reached the target + return false + } + // Loop scaling + goalns := b.benchTime.d.Nanoseconds() + prevIters := int64(b.loop.n) + b.loop.n = uint64(predictN(goalns, prevIters, t.Nanoseconds(), prevIters)) + if b.loop.n&loopPoisonMask != 0 { + // The iteration count should never get this high, but if it did we'd be + // in big trouble. + panic("loop iteration target overflow") + } + return true +} + +func (b *B) loopSlowPath() bool { + // Consistency checks + // if !b.timerOn { + // b.Fatal("B.Loop called with timer stopped") + // } + if b.loop.i&loopPoisonMask != 0 { + panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) + } + + if b.loop.n == 0 { + // It's the first call to b.Loop() in the benchmark function. + if b.benchTime.n > 0 { + // Fixed iteration count. + b.loop.n = uint64(b.benchTime.n) + } else { + // Initialize target to 1 to kick start loop scaling. + b.loop.n = 1 + } + // Within a b.Loop loop, we don't use b.N (to avoid confusion). + b.N = 0 + b.codspeed.instrument_hooks.StartBenchmark() + b.ResetTimer() + b.StartTimerWithoutMarker() + + // Start the next iteration. + b.loop.i++ + return true + } + + // Should we keep iterating? + var more bool + if b.benchTime.n > 0 { + // The iteration count is fixed, so we should have run this many and now + // be done. + if b.loop.i != uint64(b.benchTime.n) { + // We shouldn't be able to reach the slow path in this case. + panic(fmt.Sprintf("iteration count %d < fixed target %d", b.loop.i, b.benchTime.n)) + } + more = false + } else { + // Handle fixed time case + more = b.stopOrScaleBLoop() + } + if !more { + // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function + // but this will result in a huge performance degradation since the C FFI calls are expensive. + // + // The only downside of having this here, is that there's a small chance of perf sampling the + // benchmark framework code which already happens anyway because we only emit 1 pair of + // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. + endTimestamp := CurrentTimestamp() + + // Edge case: The timer is stopped in b.Loop() which prevents any further calls to + // StopTimer() from adding the benchmark markers. We have to manually submit them here, + // once the benchmark loop is done. + b.AddBenchmarkMarkers(endTimestamp) + b.codspeed.instrument_hooks.StopBenchmark() + b.sendAccumulatedTimestamps() + + // Commit iteration count + b.N = int(b.loop.n) + b.loop.done = true + return false + } + + b.StartTimerWithoutMarker() + // Start the next iteration. + b.loop.i++ + return true +} + +// Loop returns true as long as the benchmark should continue running. +// +// A typical benchmark is structured like: +// +// func Benchmark(b *testing.B) { +// ... setup ... +// for b.Loop() { +// ... code to measure ... +// } +// ... cleanup ... +// } +// +// Loop resets the benchmark timer the first time it is called in a benchmark, +// so any setup performed prior to starting the benchmark loop does not count +// toward the benchmark measurement. Likewise, when it returns false, it stops +// the timer so cleanup code is not measured. +// +// Within the body of a "for b.Loop() { ... }" loop, arguments to and +// results from function calls within the loop are kept alive, preventing +// the compiler from fully optimizing away the loop body. Currently, this is +// implemented by disabling inlining of functions called in a b.Loop loop. +// This applies only to calls syntactically between the curly braces of the loop, +// and the loop condition must be written exactly as "b.Loop()". Optimizations +// are performed as usual in any functions called by the loop. +// +// After Loop returns false, b.N contains the total number of iterations that +// ran, so the benchmark may use b.N to compute other average metrics. +// +// Prior to the introduction of Loop, benchmarks were expected to contain an +// explicit loop from 0 to b.N. Benchmarks should either use Loop or contain a +// loop to b.N, but not both. Loop offers more automatic management of the +// benchmark timer, and runs each benchmark function only once per measurement, +// whereas b.N-based benchmarks must run the benchmark function (and any +// associated setup and cleanup) several times. +func (b *B) Loop() bool { + b.StopTimerWithoutMarker() + b.SaveMeasurement() + // This is written such that the fast path is as fast as possible and can be + // inlined. + // + // There are three cases where we'll fall out of the fast path: + // + // - On the first call, both i and n are 0. + // + // - If the loop reaches the n'th iteration, then i == n and we need + // to figure out the new target iteration count or if we're done. + // + // - If the timer is stopped, it poisons the top bit of i so the slow + // path can do consistency checks and fail. + if b.loop.i < b.loop.n { + b.loop.i++ + b.StartTimerWithoutMarker() + return true + } + return b.loopSlowPath() +} + +// The loopPoison constants can be OR'd into B.loop.i to cause it to fall back +// to the slow path. +const ( + loopPoisonTimer = uint64(1 << (63 - iota)) + // If necessary, add more poison bits here. + + // loopPoisonMask is the set of all loop poison bits. (iota-1) is the index + // of the bit we just set, from which we recreate that bit mask. We subtract + // 1 to set all of the bits below that bit, then complement the result to + // get the mask. Sorry, not sorry. + loopPoisonMask = ^uint64((1 << (63 - (iota - 1))) - 1) +) + +// BenchmarkResult contains the results of a benchmark run. +type BenchmarkResult struct { + N int // The number of iterations. + T time.Duration // The total time taken. + Bytes int64 // Bytes processed in one iteration. + MemAllocs uint64 // The total number of memory allocations. + MemBytes uint64 // The total number of bytes allocated. + + CodspeedTimePerRoundNs []time.Duration + CodspeedItersPerRound []int64 + + // Extra records additional metrics reported by ReportMetric. + Extra map[string]float64 +} + +// NsPerOp returns the "ns/op" metric. +func (r BenchmarkResult) NsPerOp() int64 { + if v, ok := r.Extra["ns/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return r.T.Nanoseconds() / int64(r.N) +} + +// mbPerSec returns the "MB/s" metric. +func (r BenchmarkResult) mbPerSec() float64 { + if v, ok := r.Extra["MB/s"]; ok { + return v + } + if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { + return 0 + } + return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() +} + +// AllocsPerOp returns the "allocs/op" metric, +// which is calculated as r.MemAllocs / r.N. +func (r BenchmarkResult) AllocsPerOp() int64 { + if v, ok := r.Extra["allocs/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return int64(r.MemAllocs) / int64(r.N) +} + +// AllocedBytesPerOp returns the "B/op" metric, +// which is calculated as r.MemBytes / r.N. +func (r BenchmarkResult) AllocedBytesPerOp() int64 { + if v, ok := r.Extra["B/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return int64(r.MemBytes) / int64(r.N) +} + +// String returns a summary of the benchmark results. +// It follows the benchmark result line format from +// https://golang.org/design/14313-benchmark-format, not including the +// benchmark name. +// Extra metrics override built-in metrics of the same name. +// String does not include allocs/op or B/op, since those are reported +// by [BenchmarkResult.MemString]. +func (r BenchmarkResult) String() string { + buf := new(strings.Builder) + fmt.Fprintf(buf, "%8d", r.N) + + // Get ns/op as a float. + ns, ok := r.Extra["ns/op"] + if !ok { + ns = float64(r.T.Nanoseconds()) / float64(r.N) + } + if ns != 0 { + buf.WriteByte('\t') + prettyPrint(buf, ns, "ns/op") + } + + if mbs := r.mbPerSec(); mbs != 0 { + fmt.Fprintf(buf, "\t%7.2f MB/s", mbs) + } + + // Print extra metrics that aren't represented in the standard + // metrics. + var extraKeys []string + for k := range r.Extra { + switch k { + case "ns/op", "MB/s", "B/op", "allocs/op": + // Built-in metrics reported elsewhere. + continue + } + extraKeys = append(extraKeys, k) + } + slices.Sort(extraKeys) + for _, k := range extraKeys { + buf.WriteByte('\t') + prettyPrint(buf, r.Extra[k], k) + } + return buf.String() +} + +func prettyPrint(w io.Writer, x float64, unit string) { + // Print all numbers with 10 places before the decimal point + // and small numbers with four sig figs. Field widths are + // chosen to fit the whole part in 10 places while aligning + // the decimal point of all fractional formats. + var format string + switch y := math.Abs(x); { + case y == 0 || y >= 999.95: + format = "%10.0f %s" + case y >= 99.995: + format = "%12.1f %s" + case y >= 9.9995: + format = "%13.2f %s" + case y >= 0.99995: + format = "%14.3f %s" + case y >= 0.099995: + format = "%15.4f %s" + case y >= 0.0099995: + format = "%16.5f %s" + case y >= 0.00099995: + format = "%17.6f %s" + default: + format = "%18.7f %s" + } + fmt.Fprintf(w, format, x, unit) +} + +// MemString returns r.AllocedBytesPerOp and r.AllocsPerOp in the same format as 'go test'. +func (r BenchmarkResult) MemString() string { + return fmt.Sprintf("%8d B/op\t%8d allocs/op", + r.AllocedBytesPerOp(), r.AllocsPerOp()) +} + +// benchmarkName returns full name of benchmark including procs suffix. +func benchmarkName(name string, n int) string { + if n != 1 { + return fmt.Sprintf("%s-%d", name, n) + } + return name +} + +type benchState struct { + match *matcher + + maxLen int // The largest recorded benchmark name. + extLen int // Maximum extension length. +} + +// RunBenchmarks is an internal function but exported because it is cross-package; +// it is part of the implementation of the "go test" command. +func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { + runBenchmarks("", matchString, benchmarks) +} + +func runBenchmarks(importPath string, matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool { + // If no flag was specified, don't run benchmarks. + if len(*matchBenchmarks) == 0 { + return true + } + // Collect matching benchmarks and determine longest name. + maxprocs := 1 + for _, procs := range cpuList { + if procs > maxprocs { + maxprocs = procs + } + } + bstate := &benchState{ + match: newMatcher(matchString, *matchBenchmarks, "-test.bench", *skip), + extLen: len(benchmarkName("", maxprocs)), + } + var bs []InternalBenchmark + for _, Benchmark := range benchmarks { + if _, matched, _ := bstate.match.fullName(nil, Benchmark.Name); matched { + bs = append(bs, Benchmark) + benchName := benchmarkName(Benchmark.Name, maxprocs) + if l := len(benchName) + bstate.extLen + 1; l > bstate.maxLen { + bstate.maxLen = l + } + } + } + main := &B{ + common: common{ + name: "Main", + w: os.Stdout, + bench: true, + }, + codspeed: codspeed{ + instrument_hooks: NewInstrumentHooks(), + }, + importPath: importPath, + benchFunc: func(b *B) { + for _, Benchmark := range bs { + b.Run(Benchmark.Name, Benchmark.F) + } + }, + benchTime: benchTime, + bstate: bstate, + } + defer main.codspeed.instrument_hooks.Close() + + if Verbose() { + main.chatty = newChattyPrinter(main.w) + } + main.runN(1) + return !main.failed +} + +// processBench runs bench b for the configured CPU counts and prints the results. +func (s *benchState) processBench(b *B) { + for i, procs := range cpuList { + for j := uint(0); j < *count; j++ { + runtime.GOMAXPROCS(procs) + benchName := benchmarkName(b.name, procs) + + // If it's chatty, we've already printed this information. + if b.chatty == nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } + // Recompute the running time for all but the first iteration. + if i > 0 || j > 0 { + b = &B{ + common: common{ + signal: make(chan bool), + name: b.name, + w: b.w, + chatty: b.chatty, + bench: true, + }, + codspeed: b.codspeed, + benchFunc: b.benchFunc, + benchTime: b.benchTime, + } + b.setOutputWriter() + b.run1() + } + r := b.doBench() + if b.failed { + ensureBenchmarkIsStopped(b) + + // The output could be very long here, but probably isn't. + // We print it all, regardless, because we don't want to trim the reason + // the benchmark failed. + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), benchName, b.output) + continue + } + results := r.String() + saveCodspeedResults(b, r, benchName) + + if b.chatty != nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } + if *benchmarkMemory || b.showAllocResult { + results += "\t" + r.MemString() + } + fmt.Fprintln(b.w, results) + // Unlike with tests, we ignore the -chatty flag and always print output for + // benchmarks since the output generation time will skew the results. + if len(b.output) > 0 { + b.trimOutput() + fmt.Fprintf(b.w, "%s--- BENCH: %s\n%s", b.chatty.prefix(), benchName, b.output) + } + if p := runtime.GOMAXPROCS(-1); p != procs { + fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) + } + if b.chatty != nil && b.chatty.json { + b.chatty.Updatef("", "=== NAME %s\n", "") + } + } + } +} + +// If hideStdoutForTesting is true, Run does not print the benchName. +// This avoids a spurious print during 'go test' on package testing itself, +// which invokes b.Run in its own tests (see sub_test.go). +var hideStdoutForTesting = false + +// Run benchmarks f as a subbenchmark with the given name. It reports +// whether there were any failures. +// +// A subbenchmark is like any other benchmark. A benchmark that calls Run at +// least once will not be measured itself and will be called once with N=1. +func (b *B) Run(name string, f func(b *B)) bool { + // Since b has subbenchmarks, we will no longer run it as a benchmark itself. + // Release the lock and acquire it on exit to ensure locks stay paired. + b.hasSub.Store(true) + benchmarkLock.Unlock() + defer benchmarkLock.Lock() + + benchName, ok, partial := b.name, true, false + if b.bstate != nil { + benchName, ok, partial = b.bstate.match.fullName(&b.common, name) + } + if !ok { + return true + } + var pc [maxStackLen]uintptr + n := runtime.Callers(2, pc[:]) + sub := &B{ + common: common{ + signal: make(chan bool), + name: benchName, + parent: &b.common, + level: b.level + 1, + creator: pc[:n], + w: b.w, + chatty: b.chatty, + bench: true, + }, + codspeed: b.codspeed, + importPath: b.importPath, + benchFunc: f, + benchTime: b.benchTime, + bstate: b.bstate, + } + sub.setOutputWriter() + if partial { + // Partial name match, like -bench=X/Y matching BenchmarkX. + // Only process sub-benchmarks, if any. + sub.hasSub.Store(true) + } + + if b.chatty != nil { + labelsOnce.Do(func() { + fmt.Printf("goos: %s\n", runtime.GOOS) + fmt.Printf("goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { + fmt.Printf("pkg: %s\n", b.importPath) + } + if cpu := sysinfo.CPUName(); cpu != "" { + fmt.Printf("cpu: %s\n", cpu) + } + }) + + if !hideStdoutForTesting { + if b.chatty.json { + b.chatty.Updatef(benchName, "=== RUN %s\n", benchName) + } + fmt.Println(benchName) + } + } + + if sub.run1() { + sub.run() + } + b.add(sub.result) + return !sub.failed +} + +// add simulates running benchmarks in sequence in a single iteration. It is +// used to give some meaningful results in case func Benchmark is used in +// combination with Run. +func (b *B) add(other BenchmarkResult) { + r := &b.result + // The aggregated BenchmarkResults resemble running all subbenchmarks as + // in sequence in a single benchmark. + r.N = 1 + r.T += time.Duration(other.NsPerOp()) + if other.Bytes == 0 { + // Summing Bytes is meaningless in aggregate if not all subbenchmarks + // set it. + b.missingBytes = true + r.Bytes = 0 + } + if !b.missingBytes { + r.Bytes += other.Bytes + } + r.MemAllocs += uint64(other.AllocsPerOp()) + r.MemBytes += uint64(other.AllocedBytesPerOp()) +} + +// trimOutput shortens the output from a benchmark, which can be very long. +func (b *B) trimOutput() { + // The output is likely to appear multiple times because the benchmark + // is run multiple times, but at least it will be seen. This is not a big deal + // because benchmarks rarely print, but just in case, we trim it if it's too long. + const maxNewlines = 10 + for nlCount, j := 0, 0; j < len(b.output); j++ { + if b.output[j] == '\n' { + nlCount++ + if nlCount >= maxNewlines { + b.output = append(b.output[:j], "\n\t... [output truncated]\n"...) + break + } + } + } +} + +// A PB is used by RunParallel for running parallel benchmarks. +type PB struct { + globalN *atomic.Uint64 // shared between all worker goroutines iteration counter + grain uint64 // acquire that many iterations from globalN at once + cache uint64 // local cache of acquired iterations + bN uint64 // total number of iterations to execute (b.N) +} + +// Next reports whether there are more iterations to execute. +func (pb *PB) Next() bool { + if pb.cache == 0 { + n := pb.globalN.Add(pb.grain) + if n <= pb.bN { + pb.cache = pb.grain + } else if n < pb.bN+pb.grain { + pb.cache = pb.bN + pb.grain - n + } else { + return false + } + } + pb.cache-- + return true +} + +// RunParallel runs a benchmark in parallel. +// It creates multiple goroutines and distributes b.N iterations among them. +// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for +// non-CPU-bound benchmarks, call [B.SetParallelism] before RunParallel. +// RunParallel is usually used with the go test -cpu flag. +// +// The body function will be run in each goroutine. It should set up any +// goroutine-local state and then iterate until pb.Next returns false. +// It should not use the [B.StartTimer], [B.StopTimer], or [B.ResetTimer] functions, +// because they have global effect. It should also not call [B.Run]. +// +// RunParallel reports ns/op values as wall time for the benchmark as a whole, +// not the sum of wall time or CPU time over each parallel goroutine. +func (b *B) RunParallel(body func(*PB)) { + if b.N == 0 { + return // Nothing to do when probing. + } + // Calculate grain size as number of iterations that take ~100µs. + // 100µs is enough to amortize the overhead and provide sufficient + // dynamic load balancing. + grain := uint64(0) + if b.previousN > 0 && b.previousDuration > 0 { + grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration) + } + if grain < 1 { + grain = 1 + } + // We expect the inner loop and function call to take at least 10ns, + // so do not do more than 100µs/10ns=1e4 iterations. + if grain > 1e4 { + grain = 1e4 + } + + var n atomic.Uint64 + numProcs := b.parallelism * runtime.GOMAXPROCS(0) + var wg sync.WaitGroup + wg.Add(numProcs) + for p := 0; p < numProcs; p++ { + go func() { + defer wg.Done() + pb := &PB{ + globalN: &n, + grain: grain, + bN: uint64(b.N), + } + body(pb) + }() + } + wg.Wait() + if n.Load() <= uint64(b.N) && !b.Failed() { + b.Fatal("RunParallel: body exited without pb.Next() == false") + } +} + +// SetParallelism sets the number of goroutines used by [B.RunParallel] to p*GOMAXPROCS. +// There is usually no need to call SetParallelism for CPU-bound benchmarks. +// If p is less than 1, this call will have no effect. +func (b *B) SetParallelism(p int) { + if p >= 1 { + b.parallelism = p + } +} + +// Benchmark benchmarks a single function. It is useful for creating +// custom benchmarks that do not use the "go test" command. +// +// If f depends on testing flags, then [Init] must be used to register +// those flags before calling Benchmark and before calling [flag.Parse]. +// +// If f calls Run, the result will be an estimate of running all its +// subbenchmarks that don't call Run in sequence in a single benchmark. +func Benchmark(f func(b *B)) BenchmarkResult { + b := &B{ + common: common{ + signal: make(chan bool), + w: discard{}, + }, + benchFunc: f, + benchTime: benchTime, + } + b.setOutputWriter() + if b.run1() { + b.run() + } + return b.result +} + +type discard struct{} + +func (discard) Write(b []byte) (n int, err error) { return len(b), nil } diff --git a/go-runner/overlay/codspeed.go b/go-runner/overlay/codspeed.go new file mode 100644 index 00000000..8e9180f9 --- /dev/null +++ b/go-runner/overlay/codspeed.go @@ -0,0 +1,183 @@ +package testing + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "path/filepath" + "reflect" + "runtime" + "strings" + "time" +) + +func findGitRoot() (string, error) { + cwd, err := os.Getwd() + if err != nil { + return "", err + } + + // Search up the directory tree for .git + currentDir := cwd + for { + gitRoot := filepath.Join(currentDir, ".git") + if _, err := os.Stat(gitRoot); err == nil { + return currentDir, nil + } + + parentDir := filepath.Dir(currentDir) + if parentDir == currentDir { + // Reached the root directory + break + } + currentDir = parentDir + } + + return "", os.ErrNotExist +} + +func getGitRelativePath(absPath string) string { + canonicalizedAbsPath, err := filepath.EvalSymlinks(absPath) + if err != nil { + panic(fmt.Sprintf("failed to evaluate symlinks for path %s: %v", absPath, err)) + } + + gitRoot, err := findGitRoot() + if err != nil { + panic(fmt.Sprintf("failed to find git root: %v", err)) + } + + gitRelativePath, err := filepath.Rel(gitRoot, canonicalizedAbsPath) + if err != nil { + panic(fmt.Sprintf("failed to compute relative path from git root %s to %s: %v", gitRoot, canonicalizedAbsPath, err)) + } + + return gitRelativePath +} + +// If the benchmark execution failed, we have to ensure to stop the benchmark, which +// will send the event to the runner to also stop perf. Otherwise we could possibly +// sample a lot of data that isn't relevant. Additionally, we want to ensure that +// the emitted markers are correct (otherwise we'd have a SampleStart without a SampleStop). +func ensureBenchmarkIsStopped(b *B) { + b.codspeed.instrument_hooks.StopBenchmark() +} + +func (b *B) AddBenchmarkMarkers(endTimestamp uint64) { + if b.startTimestamp >= endTimestamp { + // This should never happen, unless we have a bug in the timer logic. + panic(fmt.Sprintf("Invalid benchmark timestamps: start timestamp (%d) is greater than or equal to end timestamp (%d)", b.startTimestamp, endTimestamp)) + } + + b.startTimestamps = append(b.startTimestamps, b.startTimestamp) + b.stopTimestamps = append(b.stopTimestamps, endTimestamp) + + // Reset to prevent accidental reuse + b.startTimestamp = 0 +} + +func removeFolderFromPath(path string, folder string) string { + parts := strings.Split(path, string(os.PathSeparator)) + + var newParts []string + for _, p := range parts { + if p != folder { + newParts = append(newParts, p) + } + } + + return filepath.Join(newParts...) +} + +func saveCodspeedResults(b *B, r BenchmarkResult, benchName string) { + type RawResults struct { + Name string `json:"name"` + Uri string `json:"uri"` + Pid int `json:"pid"` + CodspeedTimePerRoundNs []time.Duration `json:"codspeed_time_per_round_ns"` + CodspeedItersPerRound []int64 `json:"codspeed_iters_per_round"` + } + + // Find the filename of the benchmark file + var benchFile string + if b.benchFunc != nil { + pc := reflect.ValueOf(b.benchFunc).Pointer() + fn := runtime.FuncForPC(pc) + if fn == nil { + return + } + + file, _ := fn.FileLine(pc) + benchFile = file + } + + if benchFile == "" { + panic("Could not determine benchmark file name") + } + relativeBenchFile := getGitRelativePath(benchFile) + + // Build custom bench name with :: separator + var nameParts []string + current := &b.common + for current.parent != nil { + // Extract the sub-benchmark part by removing parent prefix + parentName := current.parent.name + if strings.HasPrefix(current.name, parentName+"/") { + subName := strings.TrimPrefix(current.name, parentName+"/") + nameParts = append([]string{subName}, nameParts...) + } else { + nameParts = append([]string{current.name}, nameParts...) + } + + if current.parent.name == "Main" { + break + } + current = current.parent + } + benchName = strings.Join(nameParts, "::") + benchUri := fmt.Sprintf("%s::%s", relativeBenchFile, benchName) + + rawResults := RawResults{ + Name: benchName, + Uri: benchUri, + Pid: os.Getpid(), + CodspeedTimePerRoundNs: r.CodspeedTimePerRoundNs, + CodspeedItersPerRound: r.CodspeedItersPerRound, + } + + profileDir := "@@CODSPEED_PROFILE_DIR@@" // NOTE: This will be replaced by the go-runner + if err := os.MkdirAll(filepath.Join(profileDir, "raw_results"), 0755); err != nil { + fmt.Fprintf(os.Stderr, "failed to create raw results directory: %v\n", err) + return + } + // Generate random filename to avoid any overwrites + randomBytes := make([]byte, 16) + if _, err := rand.Read(randomBytes); err != nil { + fmt.Fprintf(os.Stderr, "failed to generate random filename: %v\n", err) + return + } + rawResultsFile := filepath.Join(profileDir, "raw_results", fmt.Sprintf("%s.json", hex.EncodeToString(randomBytes))) + file, err := os.Create(rawResultsFile) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create raw results file: %v\n", err) + return + } + output, err := json.MarshalIndent(rawResults, "", " ") + if err != nil { + fmt.Fprintf(os.Stderr, "failed to marshal raw results: %v\n", err) + file.Close() + return + } + // FIXME: Don't overwrite the file if it already exists + if _, err := file.Write(output); err != nil { + fmt.Fprintf(os.Stderr, "failed to write raw results: %v\n", err) + file.Close() + return + } + defer file.Close() + + // Send pid and executed benchmark to the runner + b.codspeed.instrument_hooks.SetExecutedBenchmark(uint32(os.Getpid()), benchUri) +} diff --git a/go-runner/overlay/instrument-hooks.go b/go-runner/overlay/instrument-hooks.go new file mode 100644 index 00000000..be647a6e --- /dev/null +++ b/go-runner/overlay/instrument-hooks.go @@ -0,0 +1,97 @@ +package testing + +/* +#cgo CFLAGS: -I@@INSTRUMENT_HOOKS_DIR@@/includes -Wno-format -Wno-format-security +#include "@@INSTRUMENT_HOOKS_DIR@@/dist/core.c" + +#define MARKER_TYPE_BENCHMARK_START c_MARKER_TYPE_BENCHMARK_START__249 +#define MARKER_TYPE_BENCHMARK_END c_MARKER_TYPE_BENCHMARK_END__250 +typedef struct instruments_root_InstrumentHooks__547 InstrumentHooks; +*/ +import "C" +import ( + "os" + "runtime" + "unsafe" +) + +var integrationVersion = "@@GO_RUNNER_VERSION@@" + +type InstrumentHooks struct { + hooks *C.InstrumentHooks +} + +func NewInstrumentHooks() *InstrumentHooks { + inst := &InstrumentHooks{ + hooks: C.instrument_hooks_init(), + } + runtime.SetFinalizer(inst, (*InstrumentHooks).cleanup) + inst.SetIntegration("codspeed-go", integrationVersion) + return inst +} + +func (i *InstrumentHooks) Close() { + if i.hooks != nil { + C.instrument_hooks_deinit(i.hooks) + i.hooks = nil + runtime.SetFinalizer(i, nil) + } +} + +func (i *InstrumentHooks) cleanup() { + i.Close() +} + +func (i *InstrumentHooks) SetIntegration(name, version string) { + if i.hooks == nil { + return + } + nameC := C.CString(name) + versionC := C.CString(version) + defer C.free(unsafe.Pointer(nameC)) + defer C.free(unsafe.Pointer(versionC)) + + C.instrument_hooks_set_integration(i.hooks, (*C.uint8_t)(unsafe.Pointer(nameC)), (*C.uint8_t)(unsafe.Pointer(versionC))) +} + +func (i *InstrumentHooks) StartBenchmark() { + if i.hooks != nil { + C.instrument_hooks_start_benchmark(i.hooks) + } +} + +func (i *InstrumentHooks) StopBenchmark() { + if i.hooks != nil { + C.instrument_hooks_stop_benchmark(i.hooks) + } +} + +func (i *InstrumentHooks) SetExecutedBenchmark(pid uint32, name string) { + if i.hooks == nil { + return + } + nameC := C.CString(name) + defer C.free(unsafe.Pointer(nameC)) + + C.instrument_hooks_set_executed_benchmark(i.hooks, C.uint(pid), (*C.uint8_t)(unsafe.Pointer(nameC))) +} + +func (i *InstrumentHooks) IsInstrumented() bool { + if i.hooks == nil { + return false + } + return bool(C.instrument_hooks_is_instrumented(i.hooks)) +} + +func CurrentTimestamp() uint64 { + return uint64(C.instrument_hooks_current_timestamp()) +} + +func (i *InstrumentHooks) AddBenchmarkTimestamps(startTimestamp, endTimestamp uint64) { + if i.hooks == nil { + return + } + pid := uint32(os.Getpid()) + C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.MARKER_TYPE_BENCHMARK_START, C.uint64_t(startTimestamp)) + C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.MARKER_TYPE_BENCHMARK_END, C.uint64_t(endTimestamp)) +} diff --git a/go-runner/src/builder/discovery.rs b/go-runner/src/builder/discovery.rs deleted file mode 100644 index 4b0c0f74..00000000 --- a/go-runner/src/builder/discovery.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! Finds all the benchmarks and packages in a given Go project. - -use std::{ - hash::{DefaultHasher, Hash, Hasher}, - ops::Deref, - path::{Path, PathBuf}, - process::Command, -}; - -use crate::prelude::*; -use itertools::Itertools; -use serde::{Deserialize, Serialize}; - -/// Represents a Go package, deserialized from `go list -json` output. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct GoPackage { - /// The path to the package (e.g., "github.com/user/project/pkg/foo"). - #[serde(rename = "Dir")] - pub dir: PathBuf, - - /// The name of the package (e.g., "foo"). - #[serde(rename = "Name")] - pub name: String, - - /// The import path of the package with a package identifier (e.g., "local.dev/example-complex/internal/config [local.dev/example-complex/internal/config.test]"). - #[serde(rename = "ImportPath")] - pub import_path: String, - - /// The Go source files included in this package (e.g. `[fib.go, fib_test.go]`) - #[serde(rename = "GoFiles")] - pub go_files: Option>, - - /// The Go test files included in this package (e.g. `[fib_test.go]`). - /// This is `None` for external test packages. - #[serde(rename = "TestGoFiles")] - pub test_go_files: Option>, - - #[serde(rename = "Imports")] - pub imports: Option>, - - #[serde(rename = "TestImports")] - pub test_imports: Option>, - - #[serde(rename = "CompiledGoFiles")] - pub compiled_go_files: Option>, - - /// For external test packages, this is the package being tested - #[serde(rename = "ForTest")] - pub for_test: Option, - - #[serde(rename = "Module")] - pub module: GoModule, -} - -/// Contains information about the Go module, which contains one or more Go packages. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct GoModule { - /// The module path (e.g., "local.dev/example-complex"). - #[serde(rename = "Path")] - pub path: String, - - /// The module directory (e.g., "/home/user/go/src/local.dev/example-complex"). - #[serde(rename = "Dir")] - pub dir: PathBuf, - - /// The module go.mod file (e.g., "/home/user/go/src/local.dev/example-complex/go.mod"). - #[serde(rename = "GoMod")] - pub go_mod: PathBuf, - - /// The module version (e.g., "v1.0.0"). - #[serde(rename = "GoVersion")] - pub version: String, - - /// Whether this is the main module. - #[serde(rename = "Main")] - pub main: bool, -} - -impl GoPackage { - pub fn from_go_list_output(output: &str) -> anyhow::Result> { - // Replace all \n, then find '}{' and replace with '},{' to convert the output into a valid JSON array - let output = output.replace("\n", ""); - let output = output.replace("}{", "},{"); - - serde_json::from_str(&format!("[{output}]")).context("Failed to parse Go list output") - } - - /// Check if this package is an external test package (package name ends with _test). - /// External test packages have names ending with "_test". - pub fn is_external_test_package(&self) -> bool { - self.name.ends_with("_test") - } - - /// Returns the appropriate test files list based on whether this is an external test package. - pub fn test_files(&self) -> Option<&Vec> { - if self.is_external_test_package() { - self.go_files.as_ref() - } else { - self.test_go_files.as_ref() - } - } - - /// Returns the appropriate imports list based on whether this is an external test package. - fn test_imports_list(&self) -> &Option> { - if self.is_external_test_package() { - &self.imports - } else { - &self.test_imports - } - } - - /// Extracts the clean package import path for benchmarks. - /// - /// The import_path format is like "local.dev/example-complex/pkg/auth [local.dev/example-complex/pkg/auth.test]" - /// For external test packages (_test suffix), use the ForTest field which contains the package being tested - fn package_import_path(&self) -> anyhow::Result { - if self.is_external_test_package() { - self.for_test - .as_ref() - .ok_or_else(|| { - anyhow::anyhow!("External test package {} missing ForTest field", self.name) - }) - .cloned() - } else { - Ok(self - .import_path - .split_whitespace() - .next() - .unwrap_or(&self.import_path) - .to_string()) - } - } - - fn benchmarks(&self) -> anyhow::Result> { - let Some(test_go_files) = self.test_files() else { - bail!("No test files found for package: {}", self.name); - }; - - let package_import_path = self.package_import_path()?; - let is_external = self.is_external_test_package(); - - let mut benchmarks = Vec::new(); - for file in test_go_files.iter().sorted() { - assert!(file.ends_with("_test.go")); - - let file_path = self.dir.join(file); - let content = std::fs::read_to_string(&file_path) - .context(format!("Failed to read test file: {file_path:?}"))?; - - // Optimization: Ensure the file contains "func Benchmark" before parsing - if !content.contains("func Benchmark") { - continue; - } - - let file = match gosyn::parse_source(&content) { - Ok(ast) => ast, - Err(e) => { - warn!("Failed to parse Go file {file_path:?}: {e}"); - continue; - } - }; - - // First, collect all benchmark function names from this file - let mut found_benchmarks = Vec::new(); - for decl in &file.decl { - let gosyn::ast::Declaration::Function(func_decl) = decl else { - continue; - }; - - let func_name = &func_decl.name.name; - - // Check if function name starts with "Benchmark" - if !func_name.starts_with("Benchmark") { - continue; - } - - found_benchmarks.push(func_name.clone()); - } - - // Remove the module dir parent from the file path - let root_relative_file_path = file_path.strip_prefix(&self.module.dir).context( - format!("Couldn't strip the module dir from file path: {file_path:?}"), - )?; - - for func in found_benchmarks.into_iter().sorted() { - benchmarks.push(GoBenchmark::new( - package_import_path.clone(), - func, - root_relative_file_path.to_path_buf(), - is_external, - )); - } - } - - Ok(benchmarks) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct GoBenchmark { - /// The name of the benchmark (e.g. `BenchmarkFoo`). - pub name: String, - - /// The path to the module (e.g. `github.com/user/foo`). - module_path: String, - - /// The import alias (e.g. `foo_test_49212941`). - import_alias: String, - - /// The name with the package (e.g. `foo_test.BenchmarkFoo`). - pub qualified_name: String, - - /// The file path relative to the module directory (e.g. `pkg/foo/foo_test.go`). - pub file_path: PathBuf, - - /// Whether this benchmark is from an external test package (package foo_test). - pub is_external: bool, -} - -impl GoBenchmark { - pub fn new( - package_import_path: String, - name: String, - file_path: PathBuf, - is_external: bool, - ) -> Self { - let hash = { - let mut hasher = DefaultHasher::new(); - package_import_path.hash(&mut hasher); - hasher.finish() - }; - - let import_alias = format!("{}_{}", name.to_lowercase(), hash); - let qualified_name = format!("{}.{}", import_alias, &name); - Self { - module_path: package_import_path, - import_alias, - name, - qualified_name, - file_path, - is_external, - } - } -} - -/// Represents a package with its benchmarks. -#[derive(Debug, Clone, Serialize)] -pub struct BenchmarkPackage { - raw_package: GoPackage, - pub benchmarks: Vec, -} - -impl BenchmarkPackage { - fn new(package: GoPackage, benchmarks: Vec) -> Self { - Self { - raw_package: package, - benchmarks, - } - } - - pub fn from_project( - go_project_path: &Path, - packages: &[String], - ) -> anyhow::Result> { - let mut raw_packages = Self::run_go_list(go_project_path, packages)?; - - // Sort packages by import path to ensure deterministic order - raw_packages.sort_by(|a, b| a.import_path.cmp(&b.import_path)); - - let mut packages = Vec::new(); - for package in raw_packages { - // Filter 1: Must have test files - let Some(test_files) = package.test_files() else { - debug!("Skipping package without test files: {}", package.name); - continue; - }; - if !test_files.iter().any(|name| name.ends_with("_test.go")) { - debug!( - "Skipping package with files, but without test files: {}", - package.name - ); - continue; - } - - // Filter 2: Must have testing imports - let Some(test_imports) = package.test_imports_list() else { - debug!("Skipping package without test imports: {}", package.name); - continue; - }; - if !test_imports.iter().any(|import| import.contains("testing")) { - debug!("Skipping package without test imports: {}", package.name); - continue; - } - - // Filter 3: Must be a test executable - // Example format: `local.dev/example-complex [local.dev/example-complex.test]` - if !package.import_path.ends_with(".test]") { - debug!( - "Skipping package without test executable: {}", - package.import_path - ); - continue; - } - - // Filter 4: Must have benchmarks - let benchmarks = match package.benchmarks() { - Ok(benchmarks) => benchmarks, - Err(e) => { - warn!( - "Failed to get benchmarks for package {}: {}", - package.name, e - ); - continue; - } - }; - if benchmarks.is_empty() { - debug!("Skipping package without benchmarks: {}", package.name); - continue; - } - - packages.push(BenchmarkPackage::new(package, benchmarks)); - } - - Ok(packages) - } - - fn run_go_list(go_project_path: &Path, packages: &[String]) -> anyhow::Result> { - // Execute 'go list -test -compiled -json ' to get package information - let mut args = vec!["list", "-test", "-compiled", "-json"]; - args.extend(packages.iter().map(|s| s.as_str())); - - let output = Command::new("go") - .args(args) - .current_dir(go_project_path) - .output()?; - - if !output.status.success() { - bail!( - "Failed to execute 'go list': {}", - String::from_utf8_lossy(&output.stderr) - ); - } - - // Wrap it in '[{output}]' and parse it with serde_json - let output_str = String::from_utf8(output.stdout)?; - trace!("Go list output: {output_str}"); - - GoPackage::from_go_list_output(&output_str) - } -} - -impl Deref for BenchmarkPackage { - type Target = GoPackage; - - fn deref(&self) -> &Self::Target { - &self.raw_package - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::utils::can_build_project; - - #[rstest::rstest] - #[case::caddy("caddy")] - #[case::fzf("fzf")] - #[case::opentelemetry_go("opentelemetry-go")] - #[case::golang_benchmarks("golang-benchmarks")] - #[case::zerolog("zerolog")] - #[case::zap("zap")] - #[case::hugo("hugo")] - #[case::fuego("fuego")] - #[case::cli_runtime("cli-runtime")] - #[case::quic_go("quic-go")] - #[case::example("example")] - #[case::example_with_helper("example-with-helper")] - #[case::example_with_main("example-with-main")] - #[case::example_with_dot_go_folder("example-with-dot-go-folder")] - #[case::example_with_test_package("example-with-test-package")] - #[test_log::test] - fn test_discover_benchmarks(#[case] project_name: &str) { - let project_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("testdata/projects") - .join(project_name); - - if !can_build_project(&project_dir) { - eprintln!("Skipping test for project {project_name} due to Go version constraints."); - return; - } - - let mut packages = - BenchmarkPackage::from_project(&project_dir, &["./...".to_string()]).unwrap(); - - // Sort packages by dir to ensure deterministic order - packages.sort_by_cached_key(|pkg| pkg.dir.clone()); - - let _guard = { - let mut settings = insta::Settings::clone_current(); - settings.set_snapshot_suffix(project_name.to_string()); - settings.bind_to_scope() - }; - insta::assert_json_snapshot!(packages, { - ".**[\"raw_package\"]" => insta::dynamic_redaction(|_value, _path| "[raw_package]"), - }); - } -} diff --git a/go-runner/src/builder/mod.rs b/go-runner/src/builder/mod.rs deleted file mode 100644 index 2bb4f8a4..00000000 --- a/go-runner/src/builder/mod.rs +++ /dev/null @@ -1,199 +0,0 @@ -pub mod discovery; -pub mod patcher; -pub mod templater; - -pub use discovery::*; -use thiserror::Error; - -use crate::prelude::*; -use std::{path::Path, process::Command}; - -#[derive(Error, Debug)] -pub enum BuildError { - #[error( - "Function {function} in '{file_line}' ('{package}') is using testing.TB which is not supported because CodSpeed \ - uses a custom 'testing' package. Please modify the file to not use 'testing.TB' or contact support if you need help." - )] - TestingTBUsage { - package: String, - file_line: String, - function: String, - }, -} - -/// Check if the output contained an error about using testing.TB. Find those lines: -/// ```no_run,ignore -/// Build command error output: # go.opentelemetry.io/otel/internal/global -/// ./benchmark_codspeed.go:14:15: cannot use b (variable of type *codspeed.B) as "testing".TB value in argument to ResetForTest: *codspeed.B does not implement "testing".TB (unexported method private) -/// ``` -/// -/// Returns (package_name, filename:line_number, func) -fn parse_testing_type_error(stderr: &str) -> Option<(String, String, String)> { - use regex::Regex; - use std::sync::LazyLock; - - // Static regexes compiled once - static PACKAGE_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"^# (.+)$").unwrap()); - - // Regex to match the error line with codspeed.B and testing.B/TB - // - ^\.\/ - Starts with ./ (current directory prefix) - // - ([^:]+) - Capture group 1: Filename (everything until first colon) - // - :(\d+): - Capture group 2: Line number between colons - // - value in argument to (\w+) - Capture group 3: Function name that caused the error - // - // Example: ./fib_codspeed.go:11:14: cannot use b (variable of type *codspeed.B) as *"testing".B value in argument to Whatever - static ERROR_REGEX: LazyLock = LazyLock::new(|| { - Regex::new( - r#"^\./([^:]+):(\d+):\d+: cannot use \w+ \(variable of type \*codspeed\.B\) as (?:\*"testing"\.B|"testing"\.TB) value in argument to (\w+)"# - ).unwrap() - }); - - let mut it = stderr.lines(); - loop { - let Some(line) = it.next() else { - break; - }; - - // Look for package line - if let Some(captures) = PACKAGE_REGEX.captures(line.trim()) { - let Some(package_name) = captures.get(1).map(|m| m.as_str().to_string()) else { - continue; - }; - - // Look for error line - let Some(line) = it.next() else { - continue; - }; - if let Some(captures) = ERROR_REGEX.captures(line.trim()) { - let filename = captures - .get(1)? - .as_str() - .replace("_codspeed.go", "_test.go"); - let line_number = captures.get(2)?.as_str(); - let function = captures.get(3)?.as_str(); - - let file_line = format!("{filename}:{line_number}"); - - return Some((package_name, file_line, function.to_string())); - } - } - } - - None -} - -/// Builds a Go runner file into an executable binary -pub fn build_binary>(runner_go_path: P) -> anyhow::Result { - let runner_go_path = runner_go_path.as_ref(); - let file_dir = runner_go_path.parent().unwrap(); - let module_root = file_dir.parent().unwrap(); - - // This will be the relative path from the module root to the codspeed directory, containing - // the runner.go file. This is needed so that we compile _all_ the files within that package. - // - // This is important when we have external test packages, which are moved to the codspeed folder. - let relative_dir_path = file_dir.strip_prefix(module_root).unwrap(); - - debug!( - "Building codspeed runner binary: {:?} (root = {:?})", - module_root.join(relative_dir_path), - module_root - ); - - let binary_path = runner_go_path.with_extension("bin"); - - // Set the integration version in our testing library and include debug symbols - let ldflags = format!( - "-X github.com/CodSpeedHQ/codspeed-go/testing/capi.integrationVersion={} -s=false -w=false", - env!("CARGO_PKG_VERSION") - ); - - // Go doesn't support absolute paths, so we have to convert it to a relative path starting - // with `./{relative_dir_path}`. - let dot_slash_path = { - let p = relative_dir_path.to_str().unwrap(); - format!("./{p}") - }; - let args = vec![ - "build", - "-mod=mod", - "-tags=codspeed", - "-ldflags", - &ldflags, - "-o", - binary_path.to_str().unwrap(), - &dot_slash_path, - ]; - - let output = Command::new("go") - .args(&args) - .current_dir(module_root) - .env("GOWORK", "off") // Disable workspace mode to avoid -mod flag conflicts - .output() - .context("Failed to execute go build command")?; - - if !output.status.success() { - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - warn!("Build command output: {stdout}"); - warn!("Build command error output: {stderr}"); - - if let Some((package, file_line, func)) = parse_testing_type_error(&stderr) { - bail!(BuildError::TestingTBUsage { - package, - file_line, - function: func - }) - } - - bail!( - "Failed to build benchmark binary. Exit status: {}", - output.status - ); - } - - debug!("Successfully built binary: {binary_path:?}"); - Ok(binary_path) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_testing_type_error_basic() { - let stderr = r#" -# example -./fib_codspeed.go:11:14: cannot use b (variable of type *codspeed.B) as *"testing".B value in argument to Whatever -"#; - - let result = parse_testing_type_error(stderr); - assert_eq!( - result, - Some(( - "example".to_string(), - "fib_test.go:11".to_string(), - "Whatever".to_string() - )) - ); - } - - #[test] - fn test_parse_testing_type_error_with_package() { - let stderr = r#" -# go.opentelemetry.io/otel/internal/global -./benchmark_codspeed.go:14:15: cannot use b (variable of type *codspeed.B) as "testing".TB value in argument to ResetForTest: *codspeed.B does not implement "testing".TB (unexported method private) -"#; - - let result = parse_testing_type_error(stderr); - assert_eq!( - result, - Some(( - "go.opentelemetry.io/otel/internal/global".to_string(), - "benchmark_test.go:14".to_string(), - "ResetForTest".to_string() - )) - ); - } -} diff --git a/go-runner/src/builder/patcher.rs b/go-runner/src/builder/patcher.rs deleted file mode 100644 index 7b5a1065..00000000 --- a/go-runner/src/builder/patcher.rs +++ /dev/null @@ -1,494 +0,0 @@ -//! Patches the imports to use codspeed rather than the official "testing" package. - -use crate::prelude::*; -use itertools::Itertools; -use rayon::prelude::*; -use std::fs; -use std::path::{Path, PathBuf}; -use std::process::Command; - -/// Patcher is responsible for patching Go source files to replace imports and package names. -/// -/// It also reverts all changes on drop to avoid breaking tests. This can happen when we -/// rename or move a file, which makes it available in other packages which could lead to duplicate -/// symbols or flag definitions. -pub struct Patcher { - git_repo: PathBuf, -} - -impl Patcher { - pub fn new(git_root: &Path) -> Self { - Self { - git_repo: git_root.to_path_buf(), - } - } - - /// Replace `package main` with `package main_compat` to allow importing it from other packages. - /// Also replace `package foo_test` with `package main` for external test packages. - /// - /// Returns the previous package name, or None if no replacement was made. - fn patch_package( - source: &mut String, - replacement: Option, - ) -> anyhow::Result> { - let parsed = gosyn::parse_source(&source)?; - let prev_pkg_name = parsed.pkg_name.name; - - let replacement = replacement.or_else(|| { - if prev_pkg_name == "main" { - Some("main_compat".into()) - } else if prev_pkg_name.ends_with("_test") { - // For external test packages (package foo_test), convert to package main - // They will be placed in the codspeed/ subdirectory and built as standalone executables - Some("main".into()) - } else { - None - } - }); - - if let Some(new_name) = replacement { - let name_start = parsed.pkg_name.pos; - let name_end = name_start + prev_pkg_name.len(); - source.replace_range(name_start..name_end, &new_name); - - Ok(Some(prev_pkg_name)) - } else { - Ok(None) - } - } - - /// Patches imports and package in specific test files - /// - /// This ensures we only modify the test files that belong to the current test package, - /// avoiding conflicts when multiple test packages exist in the same directory - pub fn patch_packages_for_files(&mut self, files: &[PathBuf]) -> anyhow::Result<()> { - for go_file in files { - if !go_file.is_file() { - continue; - } - - let mut content = fs::read_to_string(go_file) - .context(format!("Failed to read Go file: {go_file:?}"))?; - if Self::patch_package(&mut content, None)?.is_some() { - fs::write(go_file, content) - .context(format!("Failed to write patched Go file: {go_file:?}"))?; - } - } - - Ok(()) - } - - /// Patches all .go files in a directory to rename "package main" to "package main_compat" - /// - /// This is needed when we have a "package main" with benchmarks that need to be imported. - /// By renaming all files in the package to "main_compat", we make it importable. - pub fn patch_all_packages_in_dir>(&mut self, dir: P) -> anyhow::Result<()> { - self.patch_packages_for_files( - &glob::glob(&dir.as_ref().join("*.go").to_string_lossy())? - .filter_map(Result::ok) - .collect::>(), - )?; - - Ok(()) - } - - fn patch_imports_for_source(source: &mut String) -> bool { - let mut modified = false; - - // If we can't parse the source, skip this replacement - // This can happen with template files or malformed Go code - let parsed = match gosyn::parse_source(&source) { - Ok(p) => p, - Err(_) => return modified, - }; - - let mut replacements = vec![]; - let mut find_replace_range = |import_path: &str, replacement: &str| { - // Optimization: check if the import path exists in the source before parsing - if !source.contains(import_path) { - return; - } - - if let Some(import) = parsed - .imports - .iter() - .find(|import| import.path.value == format!("\"{import_path}\"")) - { - let start_pos = import.path.pos; - let end_pos = start_pos + import.path.value.len(); - modified = true; - - replacements.push((start_pos..end_pos, replacement.to_string())); - } - }; - - // Then replace sub-packages like "testing/synctest" - for testing_pkg in &["fstest", "iotest", "quick", "slogtest", "synctest"] { - find_replace_range( - &format!("testing/{}", testing_pkg), - &format!( - "{testing_pkg} \"github.com/CodSpeedHQ/codspeed-go/testing/testing/{testing_pkg}\"" - ), - ); - } - - find_replace_range( - "testing", - "testing \"github.com/CodSpeedHQ/codspeed-go/testing/testing\"", - ); - find_replace_range( - "github.com/thejerf/slogassert", - "\"github.com/CodSpeedHQ/codspeed-go/pkg/slogassert\"", - ); - find_replace_range( - "github.com/frankban/quicktest", - "\"github.com/CodSpeedHQ/codspeed-go/pkg/quicktest\"", - ); - - // Apply replacements in reverse order to avoid shifting positions - for (range, replacement) in replacements - .into_iter() - .sorted_by_key(|(range, _)| range.start) - .rev() - { - source.replace_range(range, &replacement); - } - - modified - } - - pub fn patch_imports>(&mut self, folder: P) -> anyhow::Result<()> { - let folder = folder.as_ref(); - debug!("Patching imports in folder: {folder:?}"); - - // 1. Find all imports that match "testing" and replace them with codspeed equivalent - let pattern = folder.join("**/*.go"); - let patched_files = glob::glob(pattern.to_str().unwrap())? - .par_bridge() - .filter_map(Result::ok) - .filter_map(|go_file| { - // Skip directories - glob can match directories ending in .go (e.g., vendor/github.com/nats-io/nats.go) - if !go_file.is_file() { - return None; - } - - let Ok(mut content) = fs::read_to_string(&go_file) else { - error!("Failed to read Go file: {go_file:?}"); - return None; - }; - - if Self::patch_imports_for_source(&mut content) { - let Ok(_) = fs::write(&go_file, &content) else { - error!("Failed to write patched Go file: {go_file:?}"); - return None; - }; - - debug!("Patched imports in: {go_file:?}"); - } - Some(()) - }) - .count(); - debug!("Patched {} files", patched_files); - - Ok(()) - } - - pub fn rename_test_files>(&mut self, files: &[P]) -> anyhow::Result<()> { - for file in files { - let src_path = file.as_ref(); - let new_path = src_path.with_file_name( - src_path - .file_name() - .unwrap() - .to_string_lossy() - .replace("_test", "_codspeed"), - ); - fs::rename(src_path, new_path.clone())?; - } - - Ok(()) - } - - pub fn rename_and_move_test_files>( - &mut self, - files: &[P], - dst_dir: &P, - ) -> anyhow::Result<()> { - for src_path in files { - let dst_filename = src_path - .as_ref() - .file_name() - .unwrap() - .to_string_lossy() - .replace("_test.go", "_codspeed.go"); - let dst_path = dst_dir.as_ref().join(&dst_filename); - fs::rename(src_path.as_ref(), &dst_path)?; - } - - Ok(()) - } -} - -impl Drop for Patcher { - fn drop(&mut self) { - let repo_path = &self.git_repo; - - let execute_cmd = |cmd: &str| { - debug!("Executing {cmd:?} in {repo_path:?}"); - - let output = std::process::Command::new("bash") - .args(["-c", cmd]) - .current_dir(repo_path) - .output(); - if let Ok(output) = output { - if !output.status.success() { - error!( - "Failed to execute cmd: {}", - String::from_utf8_lossy(&output.stderr) - ); - } - } else { - panic!("Failed to execute command: {cmd:?}"); - } - }; - - execute_cmd("git reset --hard"); - execute_cmd("git clean -fd"); - execute_cmd("git submodule foreach git reset --hard"); - execute_cmd("git submodule foreach git clean -fd"); - } -} - -pub fn replace_pkg>(folder: P) -> anyhow::Result<()> { - let codspeed_root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap(); - let replace_arg = format!( - "github.com/CodSpeedHQ/codspeed-go={}", - codspeed_root.display() - ); - debug!("Replacing codspeed-go with {}", codspeed_root.display()); - - let output = Command::new("go") - .args(["mod", "edit", "-replace", &replace_arg]) - .current_dir(folder.as_ref()) - .output() - .context("Failed to execute 'go mod edit' command")?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - bail!("Failed to add replace directive: {}", stderr); - } - - debug!("Added local replace directive to go.mod"); - - Ok(()) -} - -/// Installs the codspeed-go dependency in the module -pub fn install_codspeed_dependency>(module_dir: P) -> anyhow::Result<()> { - let folder = module_dir.as_ref(); - debug!("Installing codspeed-go dependency in module: {folder:?}"); - - // 1. Update the go module to use the codspeed package - let version = std::env::var("CODSPEED_GO_PKG_VERSION") - .unwrap_or_else(|_| format!("v{}", env!("CARGO_PKG_VERSION"))); - let pkg = format!("github.com/CodSpeedHQ/codspeed-go@{}", version); - debug!("Installing {pkg}"); - - let mut cmd: Command = Command::new("go"); - cmd.arg("get") - .arg(pkg) - // Bypass Go proxy cache to fetch directly from source - prevents issues with - // cached versions that may have incorrect module paths or outdated content - .env("GOPROXY", "direct") - .current_dir(folder); - - let output = cmd.output().context("Failed to execute 'go get' command")?; - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - bail!("Failed to install codspeed-go dependency: {}", stderr); - } - debug!("Successfully installed codspeed-go dependency"); - - // Run 'go mod tidy' to resolve transitive dependencies - let output = Command::new("go") - .args(["mod", "tidy"]) - .current_dir(folder) - .output() - .context("Failed to execute 'go mod tidy' command")?; - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - bail!("Failed to run 'go mod tidy': {}", stderr); - } - debug!("Ran 'go mod tidy' successfully"); - - // Ensure we have the latest codspeed-go package installed. Just - // use the local one which might contain uncommitted changes. - if std::env::var("CODSPEED_GO_PKG_VERSION").is_ok() || cfg!(test) { - replace_pkg(folder)?; - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use insta::assert_snapshot; - use rstest::rstest; - - const SINGLE_IMPORT: &str = r#"package main - -import "testing" - -func TestExample(t *testing.T) { - // test code -} -"#; - - const MULTILINE_IMPORT: &str = r#"package main - -import ( - "fmt" - "testing" - "strings" -) - -func TestExample(t *testing.T) { - // test code -} -"#; - - const MULTILINE_IMPORT_WITH_TABS: &str = r#"package main - -import ( - "fmt" - "testing" - "strings" -) -"#; - - const IMPORT_WITH_COMMENTS: &str = r#"package main - -import ( - "fmt" - "testing" // for unit tests - "strings" -) -"#; - - const ALREADY_PATCHED_IMPORT: &str = r#"package main - -import testing "github.com/CodSpeedHQ/codspeed-go/compat/testing" - -func BenchmarkExample(b *testing.B) { - // benchmark code -} -"#; - - const MIXED_IMPORT_STYLES: &str = r#"package main - -import "testing" - -import ( - "fmt" - "something" -) -"#; - - const IMPORT_AT_END_OF_BLOCK: &str = r#"package main - -import ( - "fmt" - "strings" - "testing" -) -"#; - - const IMPORT_WITH_EXTRA_WHITESPACE: &str = r#"package main - -import ( - "fmt" - - "testing" - - "strings" -) -"#; - - const MULTILINE_IMPORT_WITH_TESTING_STRING: &str = r#"package main -import ( - "fmt" - "testing" -) - -func TestExample(t *testing.T) { - fmt.Println("testing") -} -"#; - - const IMPORT_WITH_TESTING_STRING: &str = r#"package main -import "testing" -import "fmt" - -func TestExample(t *testing.T) { - fmt.Println("testing") -} -"#; - - const IMPORT_TESTING_AND_SLOGASSERT: &str = r#"package main -import ( - "testing" - "fmt" - "github.com/thejerf/slogassert" -) -"#; - - const PACKAGE_MAIN: &str = r#"package main - -import "testing" - -func BenchmarkExample(b *testing.B) { - // benchmark code -} - -func TestExample(t *testing.T) { - s := "package main" -} -"#; - - const MANY_TESTING_IMPORTS: &str = r#"package subpackages -import ( - "bytes" - "io" - "testing" - "testing/fstest" - "testing/iotest" - "testing/synctest" -) -"#; - - #[rstest] - #[case("single_import_replacement", SINGLE_IMPORT)] - #[case("multiline_import_replacement", MULTILINE_IMPORT)] - #[case("multiline_import_with_tabs", MULTILINE_IMPORT_WITH_TABS)] - #[case("import_with_comments", IMPORT_WITH_COMMENTS)] - #[case("already_patched_import", ALREADY_PATCHED_IMPORT)] - #[case("mixed_import_styles", MIXED_IMPORT_STYLES)] - #[case("import_at_end_of_block", IMPORT_AT_END_OF_BLOCK)] - #[case("import_with_extra_whitespace", IMPORT_WITH_EXTRA_WHITESPACE)] - #[case("import_with_testing_string", IMPORT_WITH_TESTING_STRING)] - #[case("import_testing_and_slogassert", IMPORT_TESTING_AND_SLOGASSERT)] - #[case( - "multiline_import_with_testing_string", - MULTILINE_IMPORT_WITH_TESTING_STRING - )] - #[case("package_main", PACKAGE_MAIN)] - #[case("many_testing_imports", MANY_TESTING_IMPORTS)] - fn test_patch_go_source(#[case] test_name: &str, #[case] source: &str) { - let mut result = source.to_string(); - - Patcher::patch_imports_for_source(&mut result); - Patcher::patch_package(&mut result, None).unwrap(); - assert_snapshot!(test_name, result); - } -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks.snap deleted file mode 100644 index c3b45148..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks.snap +++ /dev/null @@ -1,1080 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "base64", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/base64 [github.com/SimonWaldherr/golang-benchmarks/base64.test]", - "TestGoFiles": [ - "base64_test.go" - ], - "TestImports": [ - "encoding/base64", - "regexp", - "testing" - ], - "CompiledGoFiles": [ - "base64_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkBase64decode", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/base64", - "import_alias": "benchmarkbase64decode_13695240289629290435", - "qualified_name": "benchmarkbase64decode_13695240289629290435.BenchmarkBase64decode", - "file_path": "base64/base64_test.go" - }, - { - "name": "BenchmarkBase64regex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/base64", - "import_alias": "benchmarkbase64regex_13695240289629290435", - "qualified_name": "benchmarkbase64regex_13695240289629290435.BenchmarkBase64regex", - "file_path": "base64/base64_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "between", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/between [github.com/SimonWaldherr/golang-benchmarks/between.test]", - "TestGoFiles": [ - "between_test.go" - ], - "TestImports": [ - "regexp", - "simonwaldherr.de/go/golibs/as", - "simonwaldherr.de/go/ranger", - "testing" - ], - "CompiledGoFiles": [ - "between_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkFulltextParse", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarkfulltextparse_9838477729561276497", - "qualified_name": "benchmarkfulltextparse_9838477729561276497.BenchmarkFulltextParse", - "file_path": "between/between_test.go" - }, - { - "name": "BenchmarkFulltextRegEx", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarkfulltextregex_9838477729561276497", - "qualified_name": "benchmarkfulltextregex_9838477729561276497.BenchmarkFulltextRegEx", - "file_path": "between/between_test.go" - }, - { - "name": "BenchmarkNumberParse", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarknumberparse_9838477729561276497", - "qualified_name": "benchmarknumberparse_9838477729561276497.BenchmarkNumberParse", - "file_path": "between/between_test.go" - }, - { - "name": "BenchmarkNumberRegEx", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarknumberregex_9838477729561276497", - "qualified_name": "benchmarknumberregex_9838477729561276497.BenchmarkNumberRegEx", - "file_path": "between/between_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "trim", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare [github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare.test]", - "TestGoFiles": [ - "caseinsensitivecompare_test.go" - ], - "TestImports": [ - "strings", - "testing" - ], - "CompiledGoFiles": [ - "caseinsensitivecompare_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkEqualFold", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarkequalfold_18307846930528351411", - "qualified_name": "benchmarkequalfold_18307846930528351411.BenchmarkEqualFold", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go" - }, - { - "name": "BenchmarkToLower", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarktolower_18307846930528351411", - "qualified_name": "benchmarktolower_18307846930528351411.BenchmarkToLower", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go" - }, - { - "name": "BenchmarkToUpper", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarktoupper_18307846930528351411", - "qualified_name": "benchmarktoupper_18307846930528351411.BenchmarkToUpper", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "concat", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/concat [github.com/SimonWaldherr/golang-benchmarks/concat.test]", - "TestGoFiles": [ - "concat_test.go" - ], - "TestImports": [ - "bytes", - "strings", - "testing" - ], - "CompiledGoFiles": [ - "concat_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkConcat", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcat_14859762629581245703", - "qualified_name": "benchmarkconcat_14859762629581245703.BenchmarkConcat", - "file_path": "concat/concat_test.go" - }, - { - "name": "BenchmarkConcatBuffer", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatbuffer_14859762629581245703", - "qualified_name": "benchmarkconcatbuffer_14859762629581245703.BenchmarkConcatBuffer", - "file_path": "concat/concat_test.go" - }, - { - "name": "BenchmarkConcatBuilder", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatbuilder_14859762629581245703", - "qualified_name": "benchmarkconcatbuilder_14859762629581245703.BenchmarkConcatBuilder", - "file_path": "concat/concat_test.go" - }, - { - "name": "BenchmarkConcatString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatstring_14859762629581245703", - "qualified_name": "benchmarkconcatstring_14859762629581245703.BenchmarkConcatString", - "file_path": "concat/concat_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "contains", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/contains [github.com/SimonWaldherr/golang-benchmarks/contains.test]", - "TestGoFiles": [ - "contains_test.go" - ], - "TestImports": [ - "bytes", - "regexp", - "strings", - "testing" - ], - "CompiledGoFiles": [ - "contains_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkCompileMatch", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcompilematch_16083491743195531531", - "qualified_name": "benchmarkcompilematch_16083491743195531531.BenchmarkCompileMatch", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkCompileMatchNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcompilematchnot_16083491743195531531", - "qualified_name": "benchmarkcompilematchnot_16083491743195531531.BenchmarkCompileMatchNot", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkContains", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontains_16083491743195531531", - "qualified_name": "benchmarkcontains_16083491743195531531.BenchmarkContains", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkContainsBytes", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsbytes_16083491743195531531", - "qualified_name": "benchmarkcontainsbytes_16083491743195531531.BenchmarkContainsBytes", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkContainsBytesNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsbytesnot_16083491743195531531", - "qualified_name": "benchmarkcontainsbytesnot_16083491743195531531.BenchmarkContainsBytesNot", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkContainsMethods", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsmethods_16083491743195531531", - "qualified_name": "benchmarkcontainsmethods_16083491743195531531.BenchmarkContainsMethods", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkContainsNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsnot_16083491743195531531", - "qualified_name": "benchmarkcontainsnot_16083491743195531531.BenchmarkContainsNot", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkMatch", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkmatch_16083491743195531531", - "qualified_name": "benchmarkmatch_16083491743195531531.BenchmarkMatch", - "file_path": "contains/contains_test.go" - }, - { - "name": "BenchmarkMatchNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkmatchnot_16083491743195531531", - "qualified_name": "benchmarkmatchnot_16083491743195531531.BenchmarkMatchNot", - "file_path": "contains/contains_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "embed", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/embed [github.com/SimonWaldherr/golang-benchmarks/embed.test]", - "TestGoFiles": [ - "embed_test.go" - ], - "TestImports": [ - "embed", - "io/ioutil", - "os", - "testing" - ], - "CompiledGoFiles": [ - "embed_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkEmbed", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkembed_10362340707071082153", - "qualified_name": "benchmarkembed_10362340707071082153.BenchmarkEmbed", - "file_path": "embed/embed_test.go" - }, - { - "name": "BenchmarkIoutilReadFile", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkioutilreadfile_10362340707071082153", - "qualified_name": "benchmarkioutilreadfile_10362340707071082153.BenchmarkIoutilReadFile", - "file_path": "embed/embed_test.go" - }, - { - "name": "BenchmarkReadFile", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkreadfile_10362340707071082153", - "qualified_name": "benchmarkreadfile_10362340707071082153.BenchmarkReadFile", - "file_path": "embed/embed_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "main", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/floodfill [github.com/SimonWaldherr/golang-benchmarks/floodfill.test]", - "TestGoFiles": [ - "floodfill_test.go" - ], - "TestImports": [ - "testing" - ], - "CompiledGoFiles": [ - "floodfill_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkFloodFillBFS", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillbfs_18158933623445949257", - "qualified_name": "benchmarkfloodfillbfs_18158933623445949257.BenchmarkFloodFillBFS", - "file_path": "floodfill/floodfill_test.go" - }, - { - "name": "BenchmarkFloodFillDFS", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfilldfs_18158933623445949257", - "qualified_name": "benchmarkfloodfilldfs_18158933623445949257.BenchmarkFloodFillDFS", - "file_path": "floodfill/floodfill_test.go" - }, - { - "name": "BenchmarkFloodFillRecursive", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillrecursive_18158933623445949257", - "qualified_name": "benchmarkfloodfillrecursive_18158933623445949257.BenchmarkFloodFillRecursive", - "file_path": "floodfill/floodfill_test.go" - }, - { - "name": "BenchmarkFloodFillStack4Way", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillstack4way_18158933623445949257", - "qualified_name": "benchmarkfloodfillstack4way_18158933623445949257.BenchmarkFloodFillStack4Way", - "file_path": "floodfill/floodfill_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "foreach", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/foreach [github.com/SimonWaldherr/golang-benchmarks/foreach.test]", - "TestGoFiles": [ - "foreach_test.go" - ], - "TestImports": [ - "testing" - ], - "CompiledGoFiles": [ - "foreach_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkForMap", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkformap_16576224277772605544", - "qualified_name": "benchmarkformap_16576224277772605544.BenchmarkForMap", - "file_path": "foreach/foreach_test.go" - }, - { - "name": "BenchmarkRangeMap", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangemap_16576224277772605544", - "qualified_name": "benchmarkrangemap_16576224277772605544.BenchmarkRangeMap", - "file_path": "foreach/foreach_test.go" - }, - { - "name": "BenchmarkRangeSlice", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangeslice_16576224277772605544", - "qualified_name": "benchmarkrangeslice_16576224277772605544.BenchmarkRangeSlice", - "file_path": "foreach/foreach_test.go" - }, - { - "name": "BenchmarkRangeSliceKey", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangeslicekey_16576224277772605544", - "qualified_name": "benchmarkrangeslicekey_16576224277772605544.BenchmarkRangeSliceKey", - "file_path": "foreach/foreach_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "hash", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/hash [github.com/SimonWaldherr/golang-benchmarks/hash.test]", - "TestGoFiles": [ - "hash_test.go" - ], - "TestImports": [ - "crypto/md5", - "crypto/sha1", - "crypto/sha256", - "crypto/sha512", - "github.com/jzelinskie/whirlpool", - "github.com/reusee/mmh3", - "github.com/zeebo/blake3", - "golang.org/x/crypto/bcrypt", - "golang.org/x/crypto/blake2b", - "golang.org/x/crypto/md4", - "golang.org/x/crypto/ripemd160", - "golang.org/x/crypto/sha3", - "hash", - "hash/adler32", - "hash/crc32", - "hash/crc64", - "hash/fnv", - "math/rand", - "testing" - ], - "CompiledGoFiles": [ - "hash_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkAdler32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkadler32_11363779915769227794", - "qualified_name": "benchmarkadler32_11363779915769227794.BenchmarkAdler32", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBCryptCost10", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost10_11363779915769227794", - "qualified_name": "benchmarkbcryptcost10_11363779915769227794.BenchmarkBCryptCost10", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBCryptCost16", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost16_11363779915769227794", - "qualified_name": "benchmarkbcryptcost16_11363779915769227794.BenchmarkBCryptCost16", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBCryptCost4", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost4_11363779915769227794", - "qualified_name": "benchmarkbcryptcost4_11363779915769227794.BenchmarkBCryptCost4", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBlake2b256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake2b256_11363779915769227794", - "qualified_name": "benchmarkblake2b256_11363779915769227794.BenchmarkBlake2b256", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBlake2b512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake2b512_11363779915769227794", - "qualified_name": "benchmarkblake2b512_11363779915769227794.BenchmarkBlake2b512", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkBlake3256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake3256_11363779915769227794", - "qualified_name": "benchmarkblake3256_11363779915769227794.BenchmarkBlake3256", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkCRC32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc32_11363779915769227794", - "qualified_name": "benchmarkcrc32_11363779915769227794.BenchmarkCRC32", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkCRC64ECMA", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc64ecma_11363779915769227794", - "qualified_name": "benchmarkcrc64ecma_11363779915769227794.BenchmarkCRC64ECMA", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkCRC64ISO", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc64iso_11363779915769227794", - "qualified_name": "benchmarkcrc64iso_11363779915769227794.BenchmarkCRC64ISO", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv128", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv128_11363779915769227794", - "qualified_name": "benchmarkfnv128_11363779915769227794.BenchmarkFnv128", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv128a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv128a_11363779915769227794", - "qualified_name": "benchmarkfnv128a_11363779915769227794.BenchmarkFnv128a", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv32_11363779915769227794", - "qualified_name": "benchmarkfnv32_11363779915769227794.BenchmarkFnv32", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv32a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv32a_11363779915769227794", - "qualified_name": "benchmarkfnv32a_11363779915769227794.BenchmarkFnv32a", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv64_11363779915769227794", - "qualified_name": "benchmarkfnv64_11363779915769227794.BenchmarkFnv64", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkFnv64a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv64a_11363779915769227794", - "qualified_name": "benchmarkfnv64a_11363779915769227794.BenchmarkFnv64a", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkMD4", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmd4_11363779915769227794", - "qualified_name": "benchmarkmd4_11363779915769227794.BenchmarkMD4", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkMD5", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmd5_11363779915769227794", - "qualified_name": "benchmarkmd5_11363779915769227794.BenchmarkMD5", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkMMH3", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmmh3_11363779915769227794", - "qualified_name": "benchmarkmmh3_11363779915769227794.BenchmarkMMH3", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkRIPEMD160", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkripemd160_11363779915769227794", - "qualified_name": "benchmarkripemd160_11363779915769227794.BenchmarkRIPEMD160", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA1", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha1_11363779915769227794", - "qualified_name": "benchmarksha1_11363779915769227794.BenchmarkSHA1", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA224", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha224_11363779915769227794", - "qualified_name": "benchmarksha224_11363779915769227794.BenchmarkSHA224", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha256_11363779915769227794", - "qualified_name": "benchmarksha256_11363779915769227794.BenchmarkSHA256", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA256Parallel", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha256parallel_11363779915769227794", - "qualified_name": "benchmarksha256parallel_11363779915769227794.BenchmarkSHA256Parallel", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA3256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha3256_11363779915769227794", - "qualified_name": "benchmarksha3256_11363779915769227794.BenchmarkSHA3256", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA3512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha3512_11363779915769227794", - "qualified_name": "benchmarksha3512_11363779915769227794.BenchmarkSHA3512", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA384", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha384_11363779915769227794", - "qualified_name": "benchmarksha384_11363779915769227794.BenchmarkSHA384", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkSHA512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha512_11363779915769227794", - "qualified_name": "benchmarksha512_11363779915769227794.BenchmarkSHA512", - "file_path": "hash/hash_test.go" - }, - { - "name": "BenchmarkWhirlpool", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkwhirlpool_11363779915769227794", - "qualified_name": "benchmarkwhirlpool_11363779915769227794.BenchmarkWhirlpool", - "file_path": "hash/hash_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "index", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/index [github.com/SimonWaldherr/golang-benchmarks/index.test]", - "TestGoFiles": [ - "index_test.go" - ], - "TestImports": [ - "math/rand", - "strconv", - "testing" - ], - "CompiledGoFiles": [ - "index_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkMapIntIndex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapintindex_15165622053927267483", - "qualified_name": "benchmarkmapintindex_15165622053927267483.BenchmarkMapIntIndex", - "file_path": "index/index_test.go" - }, - { - "name": "BenchmarkMapIntKeys", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapintkeys_15165622053927267483", - "qualified_name": "benchmarkmapintkeys_15165622053927267483.BenchmarkMapIntKeys", - "file_path": "index/index_test.go" - }, - { - "name": "BenchmarkMapStringIndex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapstringindex_15165622053927267483", - "qualified_name": "benchmarkmapstringindex_15165622053927267483.BenchmarkMapStringIndex", - "file_path": "index/index_test.go" - }, - { - "name": "BenchmarkMapStringKeys", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapstringkeys_15165622053927267483", - "qualified_name": "benchmarkmapstringkeys_15165622053927267483.BenchmarkMapStringKeys", - "file_path": "index/index_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "json", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/json [github.com/SimonWaldherr/golang-benchmarks/json.test]", - "TestGoFiles": [ - "json_test.go" - ], - "TestImports": [ - "encoding/json", - "math", - "math/big", - "testing", - "time" - ], - "CompiledGoFiles": [ - "json_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkJsonMarshal", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/json", - "import_alias": "benchmarkjsonmarshal_10512192939202823467", - "qualified_name": "benchmarkjsonmarshal_10512192939202823467.BenchmarkJsonMarshal", - "file_path": "json/json_test.go" - }, - { - "name": "BenchmarkJsonUnmarshal", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/json", - "import_alias": "benchmarkjsonunmarshal_10512192939202823467", - "qualified_name": "benchmarkjsonunmarshal_10512192939202823467.BenchmarkJsonUnmarshal", - "file_path": "json/json_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "math", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/math [github.com/SimonWaldherr/golang-benchmarks/math.test]", - "TestGoFiles": [ - "math_test.go" - ], - "TestImports": [ - "sync", - "sync/atomic", - "testing" - ], - "CompiledGoFiles": [ - "math_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkMathAtomicInt32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathatomicint32_13633368360942834619", - "qualified_name": "benchmarkmathatomicint32_13633368360942834619.BenchmarkMathAtomicInt32", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathAtomicInt64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathatomicint64_13633368360942834619", - "qualified_name": "benchmarkmathatomicint64_13633368360942834619.BenchmarkMathAtomicInt64", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathFloat32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathfloat32_13633368360942834619", - "qualified_name": "benchmarkmathfloat32_13633368360942834619.BenchmarkMathFloat32", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathFloat64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathfloat64_13633368360942834619", - "qualified_name": "benchmarkmathfloat64_13633368360942834619.BenchmarkMathFloat64", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathInt32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint32_13633368360942834619", - "qualified_name": "benchmarkmathint32_13633368360942834619.BenchmarkMathInt32", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathInt64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint64_13633368360942834619", - "qualified_name": "benchmarkmathint64_13633368360942834619.BenchmarkMathInt64", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathInt8", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint8_13633368360942834619", - "qualified_name": "benchmarkmathint8_13633368360942834619.BenchmarkMathInt8", - "file_path": "math/math_test.go" - }, - { - "name": "BenchmarkMathMutexInt", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathmutexint_13633368360942834619", - "qualified_name": "benchmarkmathmutexint_13633368360942834619.BenchmarkMathMutexInt", - "file_path": "math/math_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "parse", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/parse [github.com/SimonWaldherr/golang-benchmarks/parse.test]", - "TestGoFiles": [ - "parse_test.go" - ], - "TestImports": [ - "strconv", - "testing" - ], - "CompiledGoFiles": [ - "parse_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkParseBool", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparsebool_4725494820060427063", - "qualified_name": "benchmarkparsebool_4725494820060427063.BenchmarkParseBool", - "file_path": "parse/parse_test.go" - }, - { - "name": "BenchmarkParseFloat", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparsefloat_4725494820060427063", - "qualified_name": "benchmarkparsefloat_4725494820060427063.BenchmarkParseFloat", - "file_path": "parse/parse_test.go" - }, - { - "name": "BenchmarkParseInt", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparseint_4725494820060427063", - "qualified_name": "benchmarkparseint_4725494820060427063.BenchmarkParseInt", - "file_path": "parse/parse_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "random", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/random [github.com/SimonWaldherr/golang-benchmarks/random.test]", - "TestGoFiles": [ - "random_test.go" - ], - "TestImports": [ - "crypto/rand", - "encoding/base64", - "math/big", - "math/rand", - "testing" - ], - "CompiledGoFiles": [ - "random_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkCryptoRand", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorand_7545113576470694287", - "qualified_name": "benchmarkcryptorand_7545113576470694287.BenchmarkCryptoRand", - "file_path": "random/random_test.go" - }, - { - "name": "BenchmarkCryptoRandBytes", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorandbytes_7545113576470694287", - "qualified_name": "benchmarkcryptorandbytes_7545113576470694287.BenchmarkCryptoRandBytes", - "file_path": "random/random_test.go" - }, - { - "name": "BenchmarkCryptoRandString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorandstring_7545113576470694287", - "qualified_name": "benchmarkcryptorandstring_7545113576470694287.BenchmarkCryptoRandString", - "file_path": "random/random_test.go" - }, - { - "name": "BenchmarkMathRand", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkmathrand_7545113576470694287", - "qualified_name": "benchmarkmathrand_7545113576470694287.BenchmarkMathRand", - "file_path": "random/random_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "regexp", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/regexp [github.com/SimonWaldherr/golang-benchmarks/regexp.test]", - "TestGoFiles": [ - "regexp_test.go" - ], - "TestImports": [ - "regexp", - "simonwaldherr.de/go/golibs/regex", - "testing" - ], - "CompiledGoFiles": [ - "regexp_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkMatchString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstring_484943666522271273", - "qualified_name": "benchmarkmatchstring_484943666522271273.BenchmarkMatchString", - "file_path": "regexp/regexp_test.go" - }, - { - "name": "BenchmarkMatchStringCompiled", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstringcompiled_484943666522271273", - "qualified_name": "benchmarkmatchstringcompiled_484943666522271273.BenchmarkMatchStringCompiled", - "file_path": "regexp/regexp_test.go" - }, - { - "name": "BenchmarkMatchStringGolibs", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstringgolibs_484943666522271273", - "qualified_name": "benchmarkmatchstringgolibs_484943666522271273.BenchmarkMatchStringGolibs", - "file_path": "regexp/regexp_test.go" - } - ] - }, - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "template", - "ImportPath": "github.com/SimonWaldherr/golang-benchmarks/template [github.com/SimonWaldherr/golang-benchmarks/template.test]", - "TestGoFiles": [ - "template_test.go" - ], - "TestImports": [ - "bytes", - "html/template", - "regexp", - "testing", - "text/template" - ], - "CompiledGoFiles": [ - "template_test.go" - ], - "Module": { - "Path": "github.com/SimonWaldherr/golang-benchmarks", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.18", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkHTMLTemplate", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarkhtmltemplate_5570378712570135934", - "qualified_name": "benchmarkhtmltemplate_5570378712570135934.BenchmarkHTMLTemplate", - "file_path": "template/template_test.go" - }, - { - "name": "BenchmarkRegExp", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarkregexp_5570378712570135934", - "qualified_name": "benchmarkregexp_5570378712570135934.BenchmarkRegExp", - "file_path": "template/template_test.go" - }, - { - "name": "BenchmarkTextTemplate", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarktexttemplate_5570378712570135934", - "qualified_name": "benchmarktexttemplate_5570378712570135934.BenchmarkTextTemplate", - "file_path": "template/template_test.go" - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@caddy.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@caddy.snap deleted file mode 100644 index 2a6537d8..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@caddy.snap +++ /dev/null @@ -1,109 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkLoad", - "module_path": "github.com/caddyserver/caddy/v2", - "import_alias": "benchmarkload_11044152246690907007", - "qualified_name": "benchmarkload_11044152246690907007.BenchmarkLoad", - "file_path": "admin_test.go", - "is_external": false - }, - { - "name": "BenchmarkReplacer", - "module_path": "github.com/caddyserver/caddy/v2", - "import_alias": "benchmarkreplacer_11044152246690907007", - "qualified_name": "benchmarkreplacer_11044152246690907007.BenchmarkReplacer", - "file_path": "replacer_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMatchExpressionMatch", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkmatchexpressionmatch_847408598907947825", - "qualified_name": "benchmarkmatchexpressionmatch_847408598907947825.BenchmarkMatchExpressionMatch", - "file_path": "modules/caddyhttp/celmatcher_test.go", - "is_external": false - }, - { - "name": "BenchmarkHeaderREMatcher", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkheaderrematcher_847408598907947825", - "qualified_name": "benchmarkheaderrematcher_847408598907947825.BenchmarkHeaderREMatcher", - "file_path": "modules/caddyhttp/matchers_test.go", - "is_external": false - }, - { - "name": "BenchmarkHostMatcherWithPlaceholder", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkhostmatcherwithplaceholder_847408598907947825", - "qualified_name": "benchmarkhostmatcherwithplaceholder_847408598907947825.BenchmarkHostMatcherWithPlaceholder", - "file_path": "modules/caddyhttp/matchers_test.go", - "is_external": false - }, - { - "name": "BenchmarkHostMatcherWithoutPlaceholder", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkhostmatcherwithoutplaceholder_847408598907947825", - "qualified_name": "benchmarkhostmatcherwithoutplaceholder_847408598907947825.BenchmarkHostMatcherWithoutPlaceholder", - "file_path": "modules/caddyhttp/matchers_test.go", - "is_external": false - }, - { - "name": "BenchmarkLargeHostMatcher", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarklargehostmatcher_847408598907947825", - "qualified_name": "benchmarklargehostmatcher_847408598907947825.BenchmarkLargeHostMatcher", - "file_path": "modules/caddyhttp/matchers_test.go", - "is_external": false - }, - { - "name": "BenchmarkServer_LogRequest", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkserver_logrequest_847408598907947825", - "qualified_name": "benchmarkserver_logrequest_847408598907947825.BenchmarkServer_LogRequest", - "file_path": "modules/caddyhttp/server_test.go", - "is_external": false - }, - { - "name": "BenchmarkServer_LogRequest_NopLogger", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkserver_logrequest_noplogger_847408598907947825", - "qualified_name": "benchmarkserver_logrequest_noplogger_847408598907947825.BenchmarkServer_LogRequest_NopLogger", - "file_path": "modules/caddyhttp/server_test.go", - "is_external": false - }, - { - "name": "BenchmarkServer_LogRequest_WithTrace", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp", - "import_alias": "benchmarkserver_logrequest_withtrace_847408598907947825", - "qualified_name": "benchmarkserver_logrequest_withtrace_847408598907947825.BenchmarkServer_LogRequest_WithTrace", - "file_path": "modules/caddyhttp/server_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkOpenResponseWriter", - "module_path": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode", - "import_alias": "benchmarkopenresponsewriter_6976708135776919894", - "qualified_name": "benchmarkopenresponsewriter_6976708135776919894.BenchmarkOpenResponseWriter", - "file_path": "modules/caddyhttp/encode/encode_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@cli-runtime.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@cli-runtime.snap deleted file mode 100644 index de707735..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@cli-runtime.snap +++ /dev/null @@ -1,83 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkDiscardingPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkdiscardingprinter_4505967898862013882", - "qualified_name": "benchmarkdiscardingprinter_4505967898862013882.BenchmarkDiscardingPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkGoTemplatePrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkgotemplateprinter_4505967898862013882", - "qualified_name": "benchmarkgotemplateprinter_4505967898862013882.BenchmarkGoTemplatePrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSONPathPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkjsonpathprinter_4505967898862013882", - "qualified_name": "benchmarkjsonpathprinter_4505967898862013882.BenchmarkJSONPathPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSONPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkjsonprinter_4505967898862013882", - "qualified_name": "benchmarkjsonprinter_4505967898862013882.BenchmarkJSONPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkNamePrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarknameprinter_4505967898862013882", - "qualified_name": "benchmarknameprinter_4505967898862013882.BenchmarkNamePrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkOmitManagedFieldsPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkomitmanagedfieldsprinter_4505967898862013882", - "qualified_name": "benchmarkomitmanagedfieldsprinter_4505967898862013882.BenchmarkOmitManagedFieldsPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkTablePrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarktableprinter_4505967898862013882", - "qualified_name": "benchmarktableprinter_4505967898862013882.BenchmarkTablePrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkTypeSetterPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarktypesetterprinter_4505967898862013882", - "qualified_name": "benchmarktypesetterprinter_4505967898862013882.BenchmarkTypeSetterPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkYAMLPrinter", - "module_path": "k8s.io/cli-runtime/pkg/printers", - "import_alias": "benchmarkyamlprinter_4505967898862013882", - "qualified_name": "benchmarkyamlprinter_4505967898862013882.BenchmarkYAMLPrinter", - "file_path": "pkg/printers/bench_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-dot-go-folder.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-dot-go-folder.snap deleted file mode 100644 index b3b13cff..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-dot-go-folder.snap +++ /dev/null @@ -1,32 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExample", - "module_path": "example.com/dot-go-folder-test", - "import_alias": "benchmarkexample_7847346762563147456", - "qualified_name": "benchmarkexample_7847346762563147456.BenchmarkExample", - "file_path": "bench_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkInsideFolder", - "module_path": "example.com/dot-go-folder-test/some_package.go", - "import_alias": "benchmarkinsidefolder_9649425054511170700", - "qualified_name": "benchmarkinsidefolder_9649425054511170700.BenchmarkInsideFolder", - "file_path": "some_package.go/bench_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-helper.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-helper.snap deleted file mode 100644 index 25e94d79..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-helper.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFib", - "module_path": "example-with-helper", - "import_alias": "benchmarkfib_10228706780785555621", - "qualified_name": "benchmarkfib_10228706780785555621.BenchmarkFib", - "file_path": "fib_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-main.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-main.snap deleted file mode 100644 index 71c4d7bc..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-main.snap +++ /dev/null @@ -1,19 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFib", - "module_path": "example-with-main", - "import_alias": "benchmarkfib_7214886513345494073", - "qualified_name": "benchmarkfib_7214886513345494073.BenchmarkFib", - "file_path": "fib_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-test-package.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-test-package.snap deleted file mode 100644 index b0bf1a83..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example-with-test-package.snap +++ /dev/null @@ -1,74 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAdd", - "module_path": "example-with-test-package", - "import_alias": "benchmarkadd_15371875375851029853", - "qualified_name": "benchmarkadd_15371875375851029853.BenchmarkAdd", - "file_path": "math_test.go", - "is_external": true - }, - { - "name": "BenchmarkMultiply", - "module_path": "example-with-test-package", - "import_alias": "benchmarkmultiply_15371875375851029853", - "qualified_name": "benchmarkmultiply_15371875375851029853.BenchmarkMultiply", - "file_path": "math_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFibonacci10", - "module_path": "example-with-test-package/fib", - "import_alias": "benchmarkfibonacci10_13874902556465224305", - "qualified_name": "benchmarkfibonacci10_13874902556465224305.BenchmarkFibonacci10", - "file_path": "fib/fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkFibonacci20", - "module_path": "example-with-test-package/fib", - "import_alias": "benchmarkfibonacci20_13874902556465224305", - "qualified_name": "benchmarkfibonacci20_13874902556465224305.BenchmarkFibonacci20", - "file_path": "fib/fib_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFibonacci10", - "module_path": "example-with-test-package/fib_external", - "import_alias": "benchmarkfibonacci10_6158637354325539077", - "qualified_name": "benchmarkfibonacci10_6158637354325539077.BenchmarkFibonacci10", - "file_path": "fib_external/fib_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFibonacci20", - "module_path": "example-with-test-package/fib_external", - "import_alias": "benchmarkfibonacci20_6158637354325539077", - "qualified_name": "benchmarkfibonacci20_6158637354325539077.BenchmarkFibonacci20", - "file_path": "fib_external/fib_integration_test.go", - "is_external": true - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example.snap deleted file mode 100644 index 0ca54f63..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@example.snap +++ /dev/null @@ -1,348 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFibonacci10", - "module_path": "example", - "import_alias": "benchmarkfibonacci10_9576953055782987076", - "qualified_name": "benchmarkfibonacci10_9576953055782987076.BenchmarkFibonacci10", - "file_path": "fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkFibonacci10Parallel", - "module_path": "example", - "import_alias": "benchmarkfibonacci10parallel_9576953055782987076", - "qualified_name": "benchmarkfibonacci10parallel_9576953055782987076.BenchmarkFibonacci10Parallel", - "file_path": "fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkFibonacci20Parallel", - "module_path": "example", - "import_alias": "benchmarkfibonacci20parallel_9576953055782987076", - "qualified_name": "benchmarkfibonacci20parallel_9576953055782987076.BenchmarkFibonacci20Parallel", - "file_path": "fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkFibonacci20_Loop", - "module_path": "example", - "import_alias": "benchmarkfibonacci20_loop_9576953055782987076", - "qualified_name": "benchmarkfibonacci20_loop_9576953055782987076.BenchmarkFibonacci20_Loop", - "file_path": "fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkFibonacci20_bN", - "module_path": "example", - "import_alias": "benchmarkfibonacci20_bn_9576953055782987076", - "qualified_name": "benchmarkfibonacci20_bn_9576953055782987076.BenchmarkFibonacci20_bN", - "file_path": "fib_test.go", - "is_external": false - }, - { - "name": "BenchmarkLargeSetup", - "module_path": "example", - "import_alias": "benchmarklargesetup_9576953055782987076", - "qualified_name": "benchmarklargesetup_9576953055782987076.BenchmarkLargeSetup", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkLargeSetupInLoop", - "module_path": "example", - "import_alias": "benchmarklargesetupinloop_9576953055782987076", - "qualified_name": "benchmarklargesetupinloop_9576953055782987076.BenchmarkLargeSetupInLoop", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithOutlierMeasurementModern", - "module_path": "example", - "import_alias": "benchmarkwithoutliermeasurementmodern_9576953055782987076", - "qualified_name": "benchmarkwithoutliermeasurementmodern_9576953055782987076.BenchmarkWithOutlierMeasurementModern", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithOutlierMeasurementTraditional", - "module_path": "example", - "import_alias": "benchmarkwithoutliermeasurementtraditional_9576953055782987076", - "qualified_name": "benchmarkwithoutliermeasurementtraditional_9576953055782987076.BenchmarkWithOutlierMeasurementTraditional", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithStopModern", - "module_path": "example", - "import_alias": "benchmarkwithstopmodern_9576953055782987076", - "qualified_name": "benchmarkwithstopmodern_9576953055782987076.BenchmarkWithStopModern", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithStopTraditional", - "module_path": "example", - "import_alias": "benchmarkwithstoptraditional_9576953055782987076", - "qualified_name": "benchmarkwithstoptraditional_9576953055782987076.BenchmarkWithStopTraditional", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithoutStartupModern", - "module_path": "example", - "import_alias": "benchmarkwithoutstartupmodern_9576953055782987076", - "qualified_name": "benchmarkwithoutstartupmodern_9576953055782987076.BenchmarkWithoutStartupModern", - "file_path": "setup_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithoutStartupTraditional", - "module_path": "example", - "import_alias": "benchmarkwithoutstartuptraditional_9576953055782987076", - "qualified_name": "benchmarkwithoutstartuptraditional_9576953055782987076.BenchmarkWithoutStartupTraditional", - "file_path": "setup_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkQuicktest", - "module_path": "example/compat", - "import_alias": "benchmarkquicktest_3904647701036713533", - "qualified_name": "benchmarkquicktest_3904647701036713533.BenchmarkQuicktest", - "file_path": "compat/quicktest_test.go", - "is_external": false - }, - { - "name": "BenchmarkWithSlogAssert", - "module_path": "example/compat", - "import_alias": "benchmarkwithslogassert_3904647701036713533", - "qualified_name": "benchmarkwithslogassert_3904647701036713533.BenchmarkWithSlogAssert", - "file_path": "compat/slogassert_test.go", - "is_external": false - }, - { - "name": "BenchmarkTestifyWithNew", - "module_path": "example/compat", - "import_alias": "benchmarktestifywithnew_3904647701036713533", - "qualified_name": "benchmarktestifywithnew_3904647701036713533.BenchmarkTestifyWithNew", - "file_path": "compat/testify_test.go", - "is_external": false - }, - { - "name": "BenchmarkTestifyWithT", - "module_path": "example/compat", - "import_alias": "benchmarktestifywitht_3904647701036713533", - "qualified_name": "benchmarktestifywitht_3904647701036713533.BenchmarkTestifyWithT", - "file_path": "compat/testify_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExternalFib", - "module_path": "example/external", - "import_alias": "benchmarkexternalfib_8141020470883116639", - "qualified_name": "benchmarkexternalfib_8141020470883116639.BenchmarkExternalFib", - "file_path": "external/external_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBufferRead", - "module_path": "example/sub-packages", - "import_alias": "benchmarkbufferread_2338334068071879025", - "qualified_name": "benchmarkbufferread_2338334068071879025.BenchmarkBufferRead", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - }, - { - "name": "BenchmarkBufferWrite", - "module_path": "example/sub-packages", - "import_alias": "benchmarkbufferwrite_2338334068071879025", - "qualified_name": "benchmarkbufferwrite_2338334068071879025.BenchmarkBufferWrite", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - }, - { - "name": "BenchmarkCounterWithMutex", - "module_path": "example/sub-packages", - "import_alias": "benchmarkcounterwithmutex_2338334068071879025", - "qualified_name": "benchmarkcounterwithmutex_2338334068071879025.BenchmarkCounterWithMutex", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - }, - { - "name": "BenchmarkFSTestFS", - "module_path": "example/sub-packages", - "import_alias": "benchmarkfstestfs_2338334068071879025", - "qualified_name": "benchmarkfstestfs_2338334068071879025.BenchmarkFSTestFS", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - }, - { - "name": "BenchmarkIOTestReader", - "module_path": "example/sub-packages", - "import_alias": "benchmarkiotestreader_2338334068071879025", - "qualified_name": "benchmarkiotestreader_2338334068071879025.BenchmarkIOTestReader", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - }, - { - "name": "BenchmarkWriterFunc", - "module_path": "example/sub-packages", - "import_alias": "benchmarkwriterfunc_2338334068071879025", - "qualified_name": "benchmarkwriterfunc_2338334068071879025.BenchmarkWriterFunc", - "file_path": "sub-packages/buffer_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkSleep100ns", - "module_path": "example/timing", - "import_alias": "benchmarksleep100ns_9596130933289179795", - "qualified_name": "benchmarksleep100ns_9596130933289179795.BenchmarkSleep100ns", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep100ns_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep100ns_loop_9596130933289179795", - "qualified_name": "benchmarksleep100ns_loop_9596130933289179795.BenchmarkSleep100ns_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep100us", - "module_path": "example/timing", - "import_alias": "benchmarksleep100us_9596130933289179795", - "qualified_name": "benchmarksleep100us_9596130933289179795.BenchmarkSleep100us", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep100us_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep100us_loop_9596130933289179795", - "qualified_name": "benchmarksleep100us_loop_9596130933289179795.BenchmarkSleep100us_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep10ms", - "module_path": "example/timing", - "import_alias": "benchmarksleep10ms_9596130933289179795", - "qualified_name": "benchmarksleep10ms_9596130933289179795.BenchmarkSleep10ms", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep10ms_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep10ms_loop_9596130933289179795", - "qualified_name": "benchmarksleep10ms_loop_9596130933289179795.BenchmarkSleep10ms_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep10us", - "module_path": "example/timing", - "import_alias": "benchmarksleep10us_9596130933289179795", - "qualified_name": "benchmarksleep10us_9596130933289179795.BenchmarkSleep10us", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep10us_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep10us_loop_9596130933289179795", - "qualified_name": "benchmarksleep10us_loop_9596130933289179795.BenchmarkSleep10us_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep1ms", - "module_path": "example/timing", - "import_alias": "benchmarksleep1ms_9596130933289179795", - "qualified_name": "benchmarksleep1ms_9596130933289179795.BenchmarkSleep1ms", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep1ms_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep1ms_loop_9596130933289179795", - "qualified_name": "benchmarksleep1ms_loop_9596130933289179795.BenchmarkSleep1ms_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep1us", - "module_path": "example/timing", - "import_alias": "benchmarksleep1us_9596130933289179795", - "qualified_name": "benchmarksleep1us_9596130933289179795.BenchmarkSleep1us", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep1us_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep1us_loop_9596130933289179795", - "qualified_name": "benchmarksleep1us_loop_9596130933289179795.BenchmarkSleep1us_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep50ms", - "module_path": "example/timing", - "import_alias": "benchmarksleep50ms_9596130933289179795", - "qualified_name": "benchmarksleep50ms_9596130933289179795.BenchmarkSleep50ms", - "file_path": "timing/sleep_test.go", - "is_external": false - }, - { - "name": "BenchmarkSleep50ms_Loop", - "module_path": "example/timing", - "import_alias": "benchmarksleep50ms_loop_9596130933289179795", - "qualified_name": "benchmarksleep50ms_loop_9596130933289179795.BenchmarkSleep50ms_Loop", - "file_path": "timing/sleep_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExample", - "module_path": "example/very/nested/module", - "import_alias": "benchmarkexample_15276134930479441851", - "qualified_name": "benchmarkexample_15276134930479441851.BenchmarkExample", - "file_path": "very/nested/module/example_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fuego.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fuego.snap deleted file mode 100644 index c5a317c9..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fuego.snap +++ /dev/null @@ -1,99 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkContext_Body", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkcontext_body_1011315274854895255", - "qualified_name": "benchmarkcontext_body_1011315274854895255.BenchmarkContext_Body", - "file_path": "ctx_test.go", - "is_external": false - }, - { - "name": "BenchmarkReadJSON", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkreadjson_1011315274854895255", - "qualified_name": "benchmarkreadjson_1011315274854895255.BenchmarkReadJSON", - "file_path": "deserialization_test.go", - "is_external": false - }, - { - "name": "BenchmarkReadString", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkreadstring_1011315274854895255", - "qualified_name": "benchmarkreadstring_1011315274854895255.BenchmarkReadString", - "file_path": "deserialization_test.go", - "is_external": false - }, - { - "name": "BenchmarkHTTPError_PublicError", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkhttperror_publicerror_1011315274854895255", - "qualified_name": "benchmarkhttperror_publicerror_1011315274854895255.BenchmarkHTTPError_PublicError", - "file_path": "errors_test.go", - "is_external": false - }, - { - "name": "BenchmarkRender", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkrender_1011315274854895255", - "qualified_name": "benchmarkrender_1011315274854895255.BenchmarkRender", - "file_path": "html_test.go", - "is_external": false - }, - { - "name": "BenchmarkCamelToHuman", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkcameltohuman_1011315274854895255", - "qualified_name": "benchmarkcameltohuman_1011315274854895255.BenchmarkCamelToHuman", - "file_path": "net_http_mux_test.go", - "is_external": false - }, - { - "name": "BenchmarkRequest", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkrequest_1011315274854895255", - "qualified_name": "benchmarkrequest_1011315274854895255.BenchmarkRequest", - "file_path": "net_http_mux_test.go", - "is_external": false - }, - { - "name": "BenchmarkRoutesRegistration", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkroutesregistration_1011315274854895255", - "qualified_name": "benchmarkroutesregistration_1011315274854895255.BenchmarkRoutesRegistration", - "file_path": "openapi_test.go", - "is_external": false - }, - { - "name": "BenchmarkServer_generateOpenAPI", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkserver_generateopenapi_1011315274854895255", - "qualified_name": "benchmarkserver_generateopenapi_1011315274854895255.BenchmarkServer_generateOpenAPI", - "file_path": "openapi_test.go", - "is_external": false - }, - { - "name": "BenchmarkParsePathParams", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkparsepathparams_1011315274854895255", - "qualified_name": "benchmarkparsepathparams_1011315274854895255.BenchmarkParsePathParams", - "file_path": "params_test.go", - "is_external": false - }, - { - "name": "BenchmarkOutTransform", - "module_path": "github.com/go-fuego/fuego", - "import_alias": "benchmarkouttransform_1011315274854895255", - "qualified_name": "benchmarkouttransform_1011315274854895255.BenchmarkOutTransform", - "file_path": "serialization_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fzf.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fzf.snap deleted file mode 100644 index 511b2a67..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@fzf.snap +++ /dev/null @@ -1,35 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExtractColor", - "module_path": "github.com/junegunn/fzf/src", - "import_alias": "benchmarkextractcolor_14283034902160090855", - "qualified_name": "benchmarkextractcolor_14283034902160090855.BenchmarkExtractColor", - "file_path": "src/ansi_test.go", - "is_external": false - }, - { - "name": "BenchmarkNextAnsiEscapeSequence", - "module_path": "github.com/junegunn/fzf/src", - "import_alias": "benchmarknextansiescapesequence_14283034902160090855", - "qualified_name": "benchmarknextansiescapesequence_14283034902160090855.BenchmarkNextAnsiEscapeSequence", - "file_path": "src/ansi_test.go", - "is_external": false - }, - { - "name": "BenchmarkNextAnsiEscapeSequence_Regex", - "module_path": "github.com/junegunn/fzf/src", - "import_alias": "benchmarknextansiescapesequence_regex_14283034902160090855", - "qualified_name": "benchmarknextansiescapesequence_regex_14283034902160090855.BenchmarkNextAnsiEscapeSequence_Regex", - "file_path": "src/ansi_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@golang-benchmarks.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@golang-benchmarks.snap deleted file mode 100644 index 78eaaa47..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@golang-benchmarks.snap +++ /dev/null @@ -1,798 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBase64decode", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/base64", - "import_alias": "benchmarkbase64decode_13695240289629290435", - "qualified_name": "benchmarkbase64decode_13695240289629290435.BenchmarkBase64decode", - "file_path": "base64/base64_test.go", - "is_external": false - }, - { - "name": "BenchmarkBase64regex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/base64", - "import_alias": "benchmarkbase64regex_13695240289629290435", - "qualified_name": "benchmarkbase64regex_13695240289629290435.BenchmarkBase64regex", - "file_path": "base64/base64_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFulltextParse", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarkfulltextparse_9838477729561276497", - "qualified_name": "benchmarkfulltextparse_9838477729561276497.BenchmarkFulltextParse", - "file_path": "between/between_test.go", - "is_external": false - }, - { - "name": "BenchmarkFulltextRegEx", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarkfulltextregex_9838477729561276497", - "qualified_name": "benchmarkfulltextregex_9838477729561276497.BenchmarkFulltextRegEx", - "file_path": "between/between_test.go", - "is_external": false - }, - { - "name": "BenchmarkNumberParse", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarknumberparse_9838477729561276497", - "qualified_name": "benchmarknumberparse_9838477729561276497.BenchmarkNumberParse", - "file_path": "between/between_test.go", - "is_external": false - }, - { - "name": "BenchmarkNumberRegEx", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/between", - "import_alias": "benchmarknumberregex_9838477729561276497", - "qualified_name": "benchmarknumberregex_9838477729561276497.BenchmarkNumberRegEx", - "file_path": "between/between_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkEqualFold", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarkequalfold_18307846930528351411", - "qualified_name": "benchmarkequalfold_18307846930528351411.BenchmarkEqualFold", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go", - "is_external": false - }, - { - "name": "BenchmarkToLower", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarktolower_18307846930528351411", - "qualified_name": "benchmarktolower_18307846930528351411.BenchmarkToLower", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go", - "is_external": false - }, - { - "name": "BenchmarkToUpper", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/caseinsensitivecompare", - "import_alias": "benchmarktoupper_18307846930528351411", - "qualified_name": "benchmarktoupper_18307846930528351411.BenchmarkToUpper", - "file_path": "caseinsensitivecompare/caseinsensitivecompare_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkConcat", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcat_14859762629581245703", - "qualified_name": "benchmarkconcat_14859762629581245703.BenchmarkConcat", - "file_path": "concat/concat_test.go", - "is_external": false - }, - { - "name": "BenchmarkConcatBuffer", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatbuffer_14859762629581245703", - "qualified_name": "benchmarkconcatbuffer_14859762629581245703.BenchmarkConcatBuffer", - "file_path": "concat/concat_test.go", - "is_external": false - }, - { - "name": "BenchmarkConcatBuilder", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatbuilder_14859762629581245703", - "qualified_name": "benchmarkconcatbuilder_14859762629581245703.BenchmarkConcatBuilder", - "file_path": "concat/concat_test.go", - "is_external": false - }, - { - "name": "BenchmarkConcatString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/concat", - "import_alias": "benchmarkconcatstring_14859762629581245703", - "qualified_name": "benchmarkconcatstring_14859762629581245703.BenchmarkConcatString", - "file_path": "concat/concat_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCompileMatch", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcompilematch_16083491743195531531", - "qualified_name": "benchmarkcompilematch_16083491743195531531.BenchmarkCompileMatch", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkCompileMatchNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcompilematchnot_16083491743195531531", - "qualified_name": "benchmarkcompilematchnot_16083491743195531531.BenchmarkCompileMatchNot", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkContains", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontains_16083491743195531531", - "qualified_name": "benchmarkcontains_16083491743195531531.BenchmarkContains", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkContainsBytes", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsbytes_16083491743195531531", - "qualified_name": "benchmarkcontainsbytes_16083491743195531531.BenchmarkContainsBytes", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkContainsBytesNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsbytesnot_16083491743195531531", - "qualified_name": "benchmarkcontainsbytesnot_16083491743195531531.BenchmarkContainsBytesNot", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkContainsMethods", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsmethods_16083491743195531531", - "qualified_name": "benchmarkcontainsmethods_16083491743195531531.BenchmarkContainsMethods", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkContainsNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkcontainsnot_16083491743195531531", - "qualified_name": "benchmarkcontainsnot_16083491743195531531.BenchmarkContainsNot", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkMatch", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkmatch_16083491743195531531", - "qualified_name": "benchmarkmatch_16083491743195531531.BenchmarkMatch", - "file_path": "contains/contains_test.go", - "is_external": false - }, - { - "name": "BenchmarkMatchNot", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/contains", - "import_alias": "benchmarkmatchnot_16083491743195531531", - "qualified_name": "benchmarkmatchnot_16083491743195531531.BenchmarkMatchNot", - "file_path": "contains/contains_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkEmbed", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkembed_10362340707071082153", - "qualified_name": "benchmarkembed_10362340707071082153.BenchmarkEmbed", - "file_path": "embed/embed_test.go", - "is_external": false - }, - { - "name": "BenchmarkIoutilReadFile", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkioutilreadfile_10362340707071082153", - "qualified_name": "benchmarkioutilreadfile_10362340707071082153.BenchmarkIoutilReadFile", - "file_path": "embed/embed_test.go", - "is_external": false - }, - { - "name": "BenchmarkReadFile", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/embed", - "import_alias": "benchmarkreadfile_10362340707071082153", - "qualified_name": "benchmarkreadfile_10362340707071082153.BenchmarkReadFile", - "file_path": "embed/embed_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFloodFillBFS", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillbfs_18158933623445949257", - "qualified_name": "benchmarkfloodfillbfs_18158933623445949257.BenchmarkFloodFillBFS", - "file_path": "floodfill/floodfill_test.go", - "is_external": false - }, - { - "name": "BenchmarkFloodFillDFS", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfilldfs_18158933623445949257", - "qualified_name": "benchmarkfloodfilldfs_18158933623445949257.BenchmarkFloodFillDFS", - "file_path": "floodfill/floodfill_test.go", - "is_external": false - }, - { - "name": "BenchmarkFloodFillRecursive", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillrecursive_18158933623445949257", - "qualified_name": "benchmarkfloodfillrecursive_18158933623445949257.BenchmarkFloodFillRecursive", - "file_path": "floodfill/floodfill_test.go", - "is_external": false - }, - { - "name": "BenchmarkFloodFillStack4Way", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/floodfill", - "import_alias": "benchmarkfloodfillstack4way_18158933623445949257", - "qualified_name": "benchmarkfloodfillstack4way_18158933623445949257.BenchmarkFloodFillStack4Way", - "file_path": "floodfill/floodfill_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkForMap", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkformap_16576224277772605544", - "qualified_name": "benchmarkformap_16576224277772605544.BenchmarkForMap", - "file_path": "foreach/foreach_test.go", - "is_external": false - }, - { - "name": "BenchmarkRangeMap", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangemap_16576224277772605544", - "qualified_name": "benchmarkrangemap_16576224277772605544.BenchmarkRangeMap", - "file_path": "foreach/foreach_test.go", - "is_external": false - }, - { - "name": "BenchmarkRangeSlice", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangeslice_16576224277772605544", - "qualified_name": "benchmarkrangeslice_16576224277772605544.BenchmarkRangeSlice", - "file_path": "foreach/foreach_test.go", - "is_external": false - }, - { - "name": "BenchmarkRangeSliceKey", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/foreach", - "import_alias": "benchmarkrangeslicekey_16576224277772605544", - "qualified_name": "benchmarkrangeslicekey_16576224277772605544.BenchmarkRangeSliceKey", - "file_path": "foreach/foreach_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAdler32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkadler32_11363779915769227794", - "qualified_name": "benchmarkadler32_11363779915769227794.BenchmarkAdler32", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBCryptCost10", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost10_11363779915769227794", - "qualified_name": "benchmarkbcryptcost10_11363779915769227794.BenchmarkBCryptCost10", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBCryptCost16", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost16_11363779915769227794", - "qualified_name": "benchmarkbcryptcost16_11363779915769227794.BenchmarkBCryptCost16", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBCryptCost4", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkbcryptcost4_11363779915769227794", - "qualified_name": "benchmarkbcryptcost4_11363779915769227794.BenchmarkBCryptCost4", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBlake2b256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake2b256_11363779915769227794", - "qualified_name": "benchmarkblake2b256_11363779915769227794.BenchmarkBlake2b256", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBlake2b512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake2b512_11363779915769227794", - "qualified_name": "benchmarkblake2b512_11363779915769227794.BenchmarkBlake2b512", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkBlake3256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkblake3256_11363779915769227794", - "qualified_name": "benchmarkblake3256_11363779915769227794.BenchmarkBlake3256", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkCRC32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc32_11363779915769227794", - "qualified_name": "benchmarkcrc32_11363779915769227794.BenchmarkCRC32", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkCRC64ECMA", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc64ecma_11363779915769227794", - "qualified_name": "benchmarkcrc64ecma_11363779915769227794.BenchmarkCRC64ECMA", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkCRC64ISO", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkcrc64iso_11363779915769227794", - "qualified_name": "benchmarkcrc64iso_11363779915769227794.BenchmarkCRC64ISO", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv128", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv128_11363779915769227794", - "qualified_name": "benchmarkfnv128_11363779915769227794.BenchmarkFnv128", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv128a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv128a_11363779915769227794", - "qualified_name": "benchmarkfnv128a_11363779915769227794.BenchmarkFnv128a", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv32_11363779915769227794", - "qualified_name": "benchmarkfnv32_11363779915769227794.BenchmarkFnv32", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv32a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv32a_11363779915769227794", - "qualified_name": "benchmarkfnv32a_11363779915769227794.BenchmarkFnv32a", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv64_11363779915769227794", - "qualified_name": "benchmarkfnv64_11363779915769227794.BenchmarkFnv64", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkFnv64a", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkfnv64a_11363779915769227794", - "qualified_name": "benchmarkfnv64a_11363779915769227794.BenchmarkFnv64a", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkMD4", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmd4_11363779915769227794", - "qualified_name": "benchmarkmd4_11363779915769227794.BenchmarkMD4", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkMD5", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmd5_11363779915769227794", - "qualified_name": "benchmarkmd5_11363779915769227794.BenchmarkMD5", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkMMH3", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkmmh3_11363779915769227794", - "qualified_name": "benchmarkmmh3_11363779915769227794.BenchmarkMMH3", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkRIPEMD160", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkripemd160_11363779915769227794", - "qualified_name": "benchmarkripemd160_11363779915769227794.BenchmarkRIPEMD160", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA1", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha1_11363779915769227794", - "qualified_name": "benchmarksha1_11363779915769227794.BenchmarkSHA1", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA224", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha224_11363779915769227794", - "qualified_name": "benchmarksha224_11363779915769227794.BenchmarkSHA224", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha256_11363779915769227794", - "qualified_name": "benchmarksha256_11363779915769227794.BenchmarkSHA256", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA256Parallel", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha256parallel_11363779915769227794", - "qualified_name": "benchmarksha256parallel_11363779915769227794.BenchmarkSHA256Parallel", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA3256", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha3256_11363779915769227794", - "qualified_name": "benchmarksha3256_11363779915769227794.BenchmarkSHA3256", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA3512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha3512_11363779915769227794", - "qualified_name": "benchmarksha3512_11363779915769227794.BenchmarkSHA3512", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA384", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha384_11363779915769227794", - "qualified_name": "benchmarksha384_11363779915769227794.BenchmarkSHA384", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkSHA512", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarksha512_11363779915769227794", - "qualified_name": "benchmarksha512_11363779915769227794.BenchmarkSHA512", - "file_path": "hash/hash_test.go", - "is_external": false - }, - { - "name": "BenchmarkWhirlpool", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/hash", - "import_alias": "benchmarkwhirlpool_11363779915769227794", - "qualified_name": "benchmarkwhirlpool_11363779915769227794.BenchmarkWhirlpool", - "file_path": "hash/hash_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMapIntIndex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapintindex_15165622053927267483", - "qualified_name": "benchmarkmapintindex_15165622053927267483.BenchmarkMapIntIndex", - "file_path": "index/index_test.go", - "is_external": false - }, - { - "name": "BenchmarkMapIntKeys", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapintkeys_15165622053927267483", - "qualified_name": "benchmarkmapintkeys_15165622053927267483.BenchmarkMapIntKeys", - "file_path": "index/index_test.go", - "is_external": false - }, - { - "name": "BenchmarkMapStringIndex", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapstringindex_15165622053927267483", - "qualified_name": "benchmarkmapstringindex_15165622053927267483.BenchmarkMapStringIndex", - "file_path": "index/index_test.go", - "is_external": false - }, - { - "name": "BenchmarkMapStringKeys", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/index", - "import_alias": "benchmarkmapstringkeys_15165622053927267483", - "qualified_name": "benchmarkmapstringkeys_15165622053927267483.BenchmarkMapStringKeys", - "file_path": "index/index_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkJsonMarshal", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/json", - "import_alias": "benchmarkjsonmarshal_10512192939202823467", - "qualified_name": "benchmarkjsonmarshal_10512192939202823467.BenchmarkJsonMarshal", - "file_path": "json/json_test.go", - "is_external": false - }, - { - "name": "BenchmarkJsonUnmarshal", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/json", - "import_alias": "benchmarkjsonunmarshal_10512192939202823467", - "qualified_name": "benchmarkjsonunmarshal_10512192939202823467.BenchmarkJsonUnmarshal", - "file_path": "json/json_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMathAtomicInt32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathatomicint32_13633368360942834619", - "qualified_name": "benchmarkmathatomicint32_13633368360942834619.BenchmarkMathAtomicInt32", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathAtomicInt64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathatomicint64_13633368360942834619", - "qualified_name": "benchmarkmathatomicint64_13633368360942834619.BenchmarkMathAtomicInt64", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathFloat32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathfloat32_13633368360942834619", - "qualified_name": "benchmarkmathfloat32_13633368360942834619.BenchmarkMathFloat32", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathFloat64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathfloat64_13633368360942834619", - "qualified_name": "benchmarkmathfloat64_13633368360942834619.BenchmarkMathFloat64", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathInt32", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint32_13633368360942834619", - "qualified_name": "benchmarkmathint32_13633368360942834619.BenchmarkMathInt32", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathInt64", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint64_13633368360942834619", - "qualified_name": "benchmarkmathint64_13633368360942834619.BenchmarkMathInt64", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathInt8", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathint8_13633368360942834619", - "qualified_name": "benchmarkmathint8_13633368360942834619.BenchmarkMathInt8", - "file_path": "math/math_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathMutexInt", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/math", - "import_alias": "benchmarkmathmutexint_13633368360942834619", - "qualified_name": "benchmarkmathmutexint_13633368360942834619.BenchmarkMathMutexInt", - "file_path": "math/math_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkParseBool", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparsebool_4725494820060427063", - "qualified_name": "benchmarkparsebool_4725494820060427063.BenchmarkParseBool", - "file_path": "parse/parse_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseFloat", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparsefloat_4725494820060427063", - "qualified_name": "benchmarkparsefloat_4725494820060427063.BenchmarkParseFloat", - "file_path": "parse/parse_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseInt", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/parse", - "import_alias": "benchmarkparseint_4725494820060427063", - "qualified_name": "benchmarkparseint_4725494820060427063.BenchmarkParseInt", - "file_path": "parse/parse_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCryptoRand", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorand_7545113576470694287", - "qualified_name": "benchmarkcryptorand_7545113576470694287.BenchmarkCryptoRand", - "file_path": "random/random_test.go", - "is_external": false - }, - { - "name": "BenchmarkCryptoRandBytes", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorandbytes_7545113576470694287", - "qualified_name": "benchmarkcryptorandbytes_7545113576470694287.BenchmarkCryptoRandBytes", - "file_path": "random/random_test.go", - "is_external": false - }, - { - "name": "BenchmarkCryptoRandString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkcryptorandstring_7545113576470694287", - "qualified_name": "benchmarkcryptorandstring_7545113576470694287.BenchmarkCryptoRandString", - "file_path": "random/random_test.go", - "is_external": false - }, - { - "name": "BenchmarkMathRand", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/random", - "import_alias": "benchmarkmathrand_7545113576470694287", - "qualified_name": "benchmarkmathrand_7545113576470694287.BenchmarkMathRand", - "file_path": "random/random_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMatchString", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstring_484943666522271273", - "qualified_name": "benchmarkmatchstring_484943666522271273.BenchmarkMatchString", - "file_path": "regexp/regexp_test.go", - "is_external": false - }, - { - "name": "BenchmarkMatchStringCompiled", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstringcompiled_484943666522271273", - "qualified_name": "benchmarkmatchstringcompiled_484943666522271273.BenchmarkMatchStringCompiled", - "file_path": "regexp/regexp_test.go", - "is_external": false - }, - { - "name": "BenchmarkMatchStringGolibs", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/regexp", - "import_alias": "benchmarkmatchstringgolibs_484943666522271273", - "qualified_name": "benchmarkmatchstringgolibs_484943666522271273.BenchmarkMatchStringGolibs", - "file_path": "regexp/regexp_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHTMLTemplate", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarkhtmltemplate_5570378712570135934", - "qualified_name": "benchmarkhtmltemplate_5570378712570135934.BenchmarkHTMLTemplate", - "file_path": "template/template_test.go", - "is_external": false - }, - { - "name": "BenchmarkRegExp", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarkregexp_5570378712570135934", - "qualified_name": "benchmarkregexp_5570378712570135934.BenchmarkRegExp", - "file_path": "template/template_test.go", - "is_external": false - }, - { - "name": "BenchmarkTextTemplate", - "module_path": "github.com/SimonWaldherr/golang-benchmarks/template", - "import_alias": "benchmarktexttemplate_5570378712570135934", - "qualified_name": "benchmarktexttemplate_5570378712570135934.BenchmarkTextTemplate", - "file_path": "template/template_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo.snap deleted file mode 100644 index 1e27a141..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo.snap +++ /dev/null @@ -1,1416 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHashMap", - "module_path": "github.com/gohugoio/hugo/common/hashing", - "import_alias": "benchmarkhashmap_5113029915181216612", - "qualified_name": "benchmarkhashmap_5113029915181216612.BenchmarkHashMap", - "file_path": "common/hashing/hashing_test.go", - "is_external": false - }, - { - "name": "BenchmarkHashString", - "module_path": "github.com/gohugoio/hugo/common/hashing", - "import_alias": "benchmarkhashstring_5113029915181216612", - "qualified_name": "benchmarkhashstring_5113029915181216612.BenchmarkHashString", - "file_path": "common/hashing/hashing_test.go", - "is_external": false - }, - { - "name": "BenchmarkXXHashFromReader", - "module_path": "github.com/gohugoio/hugo/common/hashing", - "import_alias": "benchmarkxxhashfromreader_5113029915181216612", - "qualified_name": "benchmarkxxhashfromreader_5113029915181216612.BenchmarkXXHashFromReader", - "file_path": "common/hashing/hashing_test.go", - "is_external": false - }, - { - "name": "BenchmarkXXHashFromString", - "module_path": "github.com/gohugoio/hugo/common/hashing", - "import_alias": "benchmarkxxhashfromstring_5113029915181216612", - "qualified_name": "benchmarkxxhashfromstring_5113029915181216612.BenchmarkXXHashFromString", - "file_path": "common/hashing/hashing_test.go", - "is_external": false - }, - { - "name": "BenchmarkXXHashFromStringHexEncoded", - "module_path": "github.com/gohugoio/hugo/common/hashing", - "import_alias": "benchmarkxxhashfromstringhexencoded_5113029915181216612", - "qualified_name": "benchmarkxxhashfromstringhexencoded_5113029915181216612.BenchmarkXXHashFromStringHexEncoded", - "file_path": "common/hashing/hashing_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkGetMethodByName", - "module_path": "github.com/gohugoio/hugo/common/hreflect", - "import_alias": "benchmarkgetmethodbyname_9357374153552100234", - "qualified_name": "benchmarkgetmethodbyname_9357374153552100234.BenchmarkGetMethodByName", - "file_path": "common/hreflect/helpers_test.go", - "is_external": false - }, - { - "name": "BenchmarkGetMethodByNamePara", - "module_path": "github.com/gohugoio/hugo/common/hreflect", - "import_alias": "benchmarkgetmethodbynamepara_9357374153552100234", - "qualified_name": "benchmarkgetmethodbynamepara_9357374153552100234.BenchmarkGetMethodByNamePara", - "file_path": "common/hreflect/helpers_test.go", - "is_external": false - }, - { - "name": "BenchmarkIsContextType", - "module_path": "github.com/gohugoio/hugo/common/hreflect", - "import_alias": "benchmarkiscontexttype_9357374153552100234", - "qualified_name": "benchmarkiscontexttype_9357374153552100234.BenchmarkIsContextType", - "file_path": "common/hreflect/helpers_test.go", - "is_external": false - }, - { - "name": "BenchmarkIsTruthFul", - "module_path": "github.com/gohugoio/hugo/common/hreflect", - "import_alias": "benchmarkistruthful_9357374153552100234", - "qualified_name": "benchmarkistruthful_9357374153552100234.BenchmarkIsTruthFul", - "file_path": "common/hreflect/helpers_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCompileRegexp", - "module_path": "github.com/gohugoio/hugo/common/hstrings", - "import_alias": "benchmarkcompileregexp_14536616203667474779", - "qualified_name": "benchmarkcompileregexp_14536616203667474779.BenchmarkCompileRegexp", - "file_path": "common/hstrings/strings_test.go", - "is_external": false - }, - { - "name": "BenchmarkGetOrCompileRegexp", - "module_path": "github.com/gohugoio/hugo/common/hstrings", - "import_alias": "benchmarkgetorcompileregexp_14536616203667474779", - "qualified_name": "benchmarkgetorcompileregexp_14536616203667474779.BenchmarkGetOrCompileRegexp", - "file_path": "common/hstrings/strings_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTimeFormatter", - "module_path": "github.com/gohugoio/hugo/common/htime", - "import_alias": "benchmarktimeformatter_6847590086467670113", - "qualified_name": "benchmarktimeformatter_6847590086467670113.BenchmarkTimeFormatter", - "file_path": "common/htime/time_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkScratchGet", - "module_path": "github.com/gohugoio/hugo/common/maps", - "import_alias": "benchmarkscratchget_6417345363762736316", - "qualified_name": "benchmarkscratchget_6417345363762736316.BenchmarkScratchGet", - "file_path": "common/maps/scratch_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkSanitize", - "module_path": "github.com/gohugoio/hugo/common/paths", - "import_alias": "benchmarksanitize_14713041104841945695", - "qualified_name": "benchmarksanitize_14713041104841945695.BenchmarkSanitize", - "file_path": "common/paths/path_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseIdentity", - "module_path": "github.com/gohugoio/hugo/common/paths", - "import_alias": "benchmarkparseidentity_14713041104841945695", - "qualified_name": "benchmarkparseidentity_14713041104841945695.BenchmarkParseIdentity", - "file_path": "common/paths/pathparser_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkVisitLinesAfter", - "module_path": "github.com/gohugoio/hugo/common/text", - "import_alias": "benchmarkvisitlinesafter_14136773289467528674", - "qualified_name": "benchmarkvisitlinesafter_14136773289467528674.BenchmarkVisitLinesAfter", - "file_path": "common/text/transform_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkStringSort", - "module_path": "github.com/gohugoio/hugo/compare", - "import_alias": "benchmarkstringsort_3776787483196778836", - "qualified_name": "benchmarkstringsort_3776787483196778836.BenchmarkStringSort", - "file_path": "compare/compare_strings_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkDefaultConfigProvider", - "module_path": "github.com/gohugoio/hugo/config", - "import_alias": "benchmarkdefaultconfigprovider_3417273390574421001", - "qualified_name": "benchmarkdefaultconfigprovider_3417273390574421001.BenchmarkDefaultConfigProvider", - "file_path": "config/defaultConfigProvider_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkLoad", - "module_path": "github.com/gohugoio/hugo/config/allconfig", - "import_alias": "benchmarkload_152983686080391686", - "qualified_name": "benchmarkload_152983686080391686.BenchmarkLoad", - "file_path": "config/allconfig/load_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTotalWords", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarktotalwords_76596580405171165", - "qualified_name": "benchmarktotalwords_76596580405171165.BenchmarkTotalWords", - "file_path": "helpers/content_test.go", - "is_external": true - }, - { - "name": "BenchmarkTrimShortHTML", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarktrimshorthtml_76596580405171165", - "qualified_name": "benchmarktrimshorthtml_76596580405171165.BenchmarkTrimShortHTML", - "file_path": "helpers/content_test.go", - "is_external": true - }, - { - "name": "BenchmarkReaderContains", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarkreadercontains_76596580405171165", - "qualified_name": "benchmarkreadercontains_76596580405171165.BenchmarkReaderContains", - "file_path": "helpers/general_test.go", - "is_external": true - }, - { - "name": "BenchmarkUniqueStrings", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarkuniquestrings_76596580405171165", - "qualified_name": "benchmarkuniquestrings_76596580405171165.BenchmarkUniqueStrings", - "file_path": "helpers/general_test.go", - "is_external": true - }, - { - "name": "BenchmarkAbsURL", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarkabsurl_76596580405171165", - "qualified_name": "benchmarkabsurl_76596580405171165.BenchmarkAbsURL", - "file_path": "helpers/url_test.go", - "is_external": true - }, - { - "name": "BenchmarkRelURL", - "module_path": "github.com/gohugoio/hugo/helpers", - "import_alias": "benchmarkrelurl_76596580405171165", - "qualified_name": "benchmarkrelurl_76596580405171165.BenchmarkRelURL", - "file_path": "helpers/url_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHashingFs", - "module_path": "github.com/gohugoio/hugo/hugofs", - "import_alias": "benchmarkhashingfs_2018967518753075157", - "qualified_name": "benchmarkhashingfs_2018967518753075157.BenchmarkHashingFs", - "file_path": "hugofs/hashing_fs_test.go", - "is_external": false - }, - { - "name": "BenchmarkWalk", - "module_path": "github.com/gohugoio/hugo/hugofs", - "import_alias": "benchmarkwalk_2018967518753075157", - "qualified_name": "benchmarkwalk_2018967518753075157.BenchmarkWalk", - "file_path": "hugofs/walk_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkGetGlob", - "module_path": "github.com/gohugoio/hugo/hugofs/glob", - "import_alias": "benchmarkgetglob_10959439052270934151", - "qualified_name": "benchmarkgetglob_10959439052270934151.BenchmarkGetGlob", - "file_path": "hugofs/glob/glob_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCascade", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkcascade_1700044546413486578", - "qualified_name": "benchmarkcascade_1700044546413486578.BenchmarkCascade", - "file_path": "hugolib/cascade_test.go", - "is_external": false - }, - { - "name": "BenchmarkCascadeTarget", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkcascadetarget_1700044546413486578", - "qualified_name": "benchmarkcascadetarget_1700044546413486578.BenchmarkCascadeTarget", - "file_path": "hugolib/cascade_test.go", - "is_external": false - }, - { - "name": "BenchmarkBaseline", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkbaseline_1700044546413486578", - "qualified_name": "benchmarkbaseline_1700044546413486578.BenchmarkBaseline", - "file_path": "hugolib/hugo_smoke_test.go", - "is_external": false - }, - { - "name": "BenchmarkGetPage", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkgetpage_1700044546413486578", - "qualified_name": "benchmarkgetpage_1700044546413486578.BenchmarkGetPage", - "file_path": "hugolib/pagecollections_test.go", - "is_external": false - }, - { - "name": "BenchmarkGetPageRegular", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkgetpageregular_1700044546413486578", - "qualified_name": "benchmarkgetpageregular_1700044546413486578.BenchmarkGetPageRegular", - "file_path": "hugolib/pagecollections_test.go", - "is_external": false - }, - { - "name": "BenchmarkMergeByLanguage", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkmergebylanguage_1700044546413486578", - "qualified_name": "benchmarkmergebylanguage_1700044546413486578.BenchmarkMergeByLanguage", - "file_path": "hugolib/pages_language_merge_test.go", - "is_external": false - }, - { - "name": "BenchmarkPagePageCollections", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkpagepagecollections_1700044546413486578", - "qualified_name": "benchmarkpagepagecollections_1700044546413486578.BenchmarkPagePageCollections", - "file_path": "hugolib/pages_test.go", - "is_external": false - }, - { - "name": "BenchmarkPagesPrevNext", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkpagesprevnext_1700044546413486578", - "qualified_name": "benchmarkpagesprevnext_1700044546413486578.BenchmarkPagesPrevNext", - "file_path": "hugolib/pages_test.go", - "is_external": false - }, - { - "name": "BenchmarkRebuildContentFileChange", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkrebuildcontentfilechange_1700044546413486578", - "qualified_name": "benchmarkrebuildcontentfilechange_1700044546413486578.BenchmarkRebuildContentFileChange", - "file_path": "hugolib/rebuild_test.go", - "is_external": false - }, - { - "name": "BenchmarkResourceChainPostProcess", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkresourcechainpostprocess_1700044546413486578", - "qualified_name": "benchmarkresourcechainpostprocess_1700044546413486578.BenchmarkResourceChainPostProcess", - "file_path": "hugolib/resource_chain_test.go", - "is_external": false - }, - { - "name": "BenchmarkReplaceShortcodeTokens", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkreplaceshortcodetokens_1700044546413486578", - "qualified_name": "benchmarkreplaceshortcodetokens_1700044546413486578.BenchmarkReplaceShortcodeTokens", - "file_path": "hugolib/shortcode_test.go", - "is_external": false - }, - { - "name": "BenchmarkShortcodesInSite", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarkshortcodesinsite_1700044546413486578", - "qualified_name": "benchmarkshortcodesinsite_1700044546413486578.BenchmarkShortcodesInSite", - "file_path": "hugolib/shortcode_test.go", - "is_external": false - }, - { - "name": "BenchmarkSiteNew", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarksitenew_1700044546413486578", - "qualified_name": "benchmarksitenew_1700044546413486578.BenchmarkSiteNew", - "file_path": "hugolib/site_benchmark_new_test.go", - "is_external": false - }, - { - "name": "BenchmarkTaxonomiesGetTerms", - "module_path": "github.com/gohugoio/hugo/hugolib", - "import_alias": "benchmarktaxonomiesgetterms_1700044546413486578", - "qualified_name": "benchmarktaxonomiesgetterms_1700044546413486578.BenchmarkTaxonomiesGetTerms", - "file_path": "hugolib/taxonomy_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTreeInsert", - "module_path": "github.com/gohugoio/hugo/hugolib/doctree", - "import_alias": "benchmarktreeinsert_10776930824105248872", - "qualified_name": "benchmarktreeinsert_10776930824105248872.BenchmarkTreeInsert", - "file_path": "hugolib/doctree/nodeshiftree_test.go", - "is_external": true - }, - { - "name": "BenchmarkWalk", - "module_path": "github.com/gohugoio/hugo/hugolib/doctree", - "import_alias": "benchmarkwalk_10776930824105248872", - "qualified_name": "benchmarkwalk_10776930824105248872.BenchmarkWalk", - "file_path": "hugolib/doctree/nodeshiftree_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHash", - "module_path": "github.com/gohugoio/hugo/hugolib/pagesfromdata", - "import_alias": "benchmarkhash_17303803225052856470", - "qualified_name": "benchmarkhash_17303803225052856470.BenchmarkHash", - "file_path": "hugolib/pagesfromdata/pagesfromgotmpl_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkSegmentsMatch", - "module_path": "github.com/gohugoio/hugo/hugolib/segments", - "import_alias": "benchmarksegmentsmatch_12038842643177664133", - "qualified_name": "benchmarksegmentsmatch_12038842643177664133.BenchmarkSegmentsMatch", - "file_path": "hugolib/segments/segments_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkFinder", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkfinder_12445121846465317058", - "qualified_name": "benchmarkfinder_12445121846465317058.BenchmarkFinder", - "file_path": "identity/finder_test.go", - "is_external": true - }, - { - "name": "BenchmarkIdentityManager", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkidentitymanager_12445121846465317058", - "qualified_name": "benchmarkidentitymanager_12445121846465317058.BenchmarkIdentityManager", - "file_path": "identity/identity_test.go", - "is_external": true - }, - { - "name": "BenchmarkIsNotDependent", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkisnotdependent_12445121846465317058", - "qualified_name": "benchmarkisnotdependent_12445121846465317058.BenchmarkIsNotDependent", - "file_path": "identity/identity_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExecuteGreet", - "module_path": "github.com/gohugoio/hugo/internal/warpc", - "import_alias": "benchmarkexecutegreet_5409103899159522076", - "qualified_name": "benchmarkexecutegreet_5409103899159522076.BenchmarkExecuteGreet", - "file_path": "internal/warpc/warpc_test.go", - "is_external": false - }, - { - "name": "BenchmarkExecuteGreetPara", - "module_path": "github.com/gohugoio/hugo/internal/warpc", - "import_alias": "benchmarkexecutegreetpara_5409103899159522076", - "qualified_name": "benchmarkexecutegreetpara_5409103899159522076.BenchmarkExecuteGreetPara", - "file_path": "internal/warpc/warpc_test.go", - "is_external": false - }, - { - "name": "BenchmarkExecuteKatex", - "module_path": "github.com/gohugoio/hugo/internal/warpc", - "import_alias": "benchmarkexecutekatex_5409103899159522076", - "qualified_name": "benchmarkexecutekatex_5409103899159522076.BenchmarkExecuteKatex", - "file_path": "internal/warpc/warpc_test.go", - "is_external": false - }, - { - "name": "BenchmarkExecuteKatexPara", - "module_path": "github.com/gohugoio/hugo/internal/warpc", - "import_alias": "benchmarkexecutekatexpara_5409103899159522076", - "qualified_name": "benchmarkexecutekatexpara_5409103899159522076.BenchmarkExecuteKatexPara", - "file_path": "internal/warpc/warpc_test.go", - "is_external": false - }, - { - "name": "BenchmarkKatexStartStop", - "module_path": "github.com/gohugoio/hugo/internal/warpc", - "import_alias": "benchmarkkatexstartstop_5409103899159522076", - "qualified_name": "benchmarkkatexstartstop_5409103899159522076.BenchmarkKatexStartStop", - "file_path": "internal/warpc/warpc_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCollator", - "module_path": "github.com/gohugoio/hugo/langs", - "import_alias": "benchmarkcollator_11016030763065786343", - "qualified_name": "benchmarkcollator_11016030763065786343.BenchmarkCollator", - "file_path": "langs/language_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkI18nTranslate", - "module_path": "github.com/gohugoio/hugo/langs/i18n", - "import_alias": "benchmarki18ntranslate_13243728170525625298", - "qualified_name": "benchmarki18ntranslate_13243728170525625298.BenchmarkI18nTranslate", - "file_path": "langs/i18n/i18n_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkSanitizeAnchorName", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarksanitizeanchorname_5159563046487902237", - "qualified_name": "benchmarksanitizeanchorname_5159563046487902237.BenchmarkSanitizeAnchorName", - "file_path": "markup/goldmark/autoid_test.go", - "is_external": false - }, - { - "name": "BenchmarkSanitizeAnchorNameAsciiOnly", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarksanitizeanchornameasciionly_5159563046487902237", - "qualified_name": "benchmarksanitizeanchornameasciionly_5159563046487902237.BenchmarkSanitizeAnchorNameAsciiOnly", - "file_path": "markup/goldmark/autoid_test.go", - "is_external": false - }, - { - "name": "BenchmarkSanitizeAnchorNameBlackfriday", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarksanitizeanchornameblackfriday_5159563046487902237", - "qualified_name": "benchmarksanitizeanchornameblackfriday_5159563046487902237.BenchmarkSanitizeAnchorNameBlackfriday", - "file_path": "markup/goldmark/autoid_test.go", - "is_external": false - }, - { - "name": "BenchmarkSanitizeAnchorNameString", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarksanitizeanchornamestring_5159563046487902237", - "qualified_name": "benchmarksanitizeanchornamestring_5159563046487902237.BenchmarkSanitizeAnchorNameString", - "file_path": "markup/goldmark/autoid_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCodeblocks", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarkcodeblocks_5159563046487902237", - "qualified_name": "benchmarkcodeblocks_5159563046487902237.BenchmarkCodeblocks", - "file_path": "markup/goldmark/goldmark_integration_test.go", - "is_external": true - }, - { - "name": "BenchmarkRenderHooks", - "module_path": "github.com/gohugoio/hugo/markup/goldmark", - "import_alias": "benchmarkrenderhooks_5159563046487902237", - "qualified_name": "benchmarkrenderhooks_5159563046487902237.BenchmarkRenderHooks", - "file_path": "markup/goldmark/goldmark_integration_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkWrap", - "module_path": "github.com/gohugoio/hugo/markup/goldmark/hugocontext", - "import_alias": "benchmarkwrap_46586337699277623", - "qualified_name": "benchmarkwrap_46586337699277623.BenchmarkWrap", - "file_path": "markup/goldmark/hugocontext/hugocontext_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkToc", - "module_path": "github.com/gohugoio/hugo/markup/tableofcontents", - "import_alias": "benchmarktoc_7685652659533225032", - "qualified_name": "benchmarktoc_7685652659533225032.BenchmarkToc", - "file_path": "markup/tableofcontents/tableofcontents_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTypeOps", - "module_path": "github.com/gohugoio/hugo/media", - "import_alias": "benchmarktypeops_5964443826173887463", - "qualified_name": "benchmarktypeops_5964443826173887463.BenchmarkTypeOps", - "file_path": "media/mediaType_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHowSimilar", - "module_path": "github.com/gohugoio/hugo/metrics", - "import_alias": "benchmarkhowsimilar_14889918854829962813", - "qualified_name": "benchmarkhowsimilar_14889918854829962813.BenchmarkHowSimilar", - "file_path": "metrics/metrics_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkDecodeYAMLToMap", - "module_path": "github.com/gohugoio/hugo/parser/metadecoders", - "import_alias": "benchmarkdecodeyamltomap_9459021737728421882", - "qualified_name": "benchmarkdecodeyamltomap_9459021737728421882.BenchmarkDecodeYAMLToMap", - "file_path": "parser/metadecoders/decoder_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringifyMapKeysIntegers", - "module_path": "github.com/gohugoio/hugo/parser/metadecoders", - "import_alias": "benchmarkstringifymapkeysintegers_9459021737728421882", - "qualified_name": "benchmarkstringifymapkeysintegers_9459021737728421882.BenchmarkStringifyMapKeysIntegers", - "file_path": "parser/metadecoders/decoder_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringifyMapKeysStringsOnlyInterfaceMaps", - "module_path": "github.com/gohugoio/hugo/parser/metadecoders", - "import_alias": "benchmarkstringifymapkeysstringsonlyinterfacemaps_9459021737728421882", - "qualified_name": "benchmarkstringifymapkeysstringsonlyinterfacemaps_9459021737728421882.BenchmarkStringifyMapKeysStringsOnlyInterfaceMaps", - "file_path": "parser/metadecoders/decoder_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringifyMapKeysStringsOnlyStringMaps", - "module_path": "github.com/gohugoio/hugo/parser/metadecoders", - "import_alias": "benchmarkstringifymapkeysstringsonlystringmaps_9459021737728421882", - "qualified_name": "benchmarkstringifymapkeysstringsonlystringmaps_9459021737728421882.BenchmarkStringifyMapKeysStringsOnlyStringMaps", - "file_path": "parser/metadecoders/decoder_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkShortcodeLexer", - "module_path": "github.com/gohugoio/hugo/parser/pageparser", - "import_alias": "benchmarkshortcodelexer_8462163296422208886", - "qualified_name": "benchmarkshortcodelexer_8462163296422208886.BenchmarkShortcodeLexer", - "file_path": "parser/pageparser/pageparser_shortcode_test.go", - "is_external": false - }, - { - "name": "BenchmarkHasShortcode", - "module_path": "github.com/gohugoio/hugo/parser/pageparser", - "import_alias": "benchmarkhasshortcode_8462163296422208886", - "qualified_name": "benchmarkhasshortcode_8462163296422208886.BenchmarkHasShortcode", - "file_path": "parser/pageparser/pageparser_test.go", - "is_external": false - }, - { - "name": "BenchmarkParse", - "module_path": "github.com/gohugoio/hugo/parser/pageparser", - "import_alias": "benchmarkparse_8462163296422208886", - "qualified_name": "benchmarkparse_8462163296422208886.BenchmarkParse", - "file_path": "parser/pageparser/pageparser_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkElementsCollectorWriter", - "module_path": "github.com/gohugoio/hugo/publisher", - "import_alias": "benchmarkelementscollectorwriter_675901470590545190", - "qualified_name": "benchmarkelementscollectorwriter_675901470590545190.BenchmarkElementsCollectorWriter", - "file_path": "publisher/htmlElementsCollector_test.go", - "is_external": false - }, - { - "name": "BenchmarkElementsCollectorWriterPre", - "module_path": "github.com/gohugoio/hugo/publisher", - "import_alias": "benchmarkelementscollectorwriterpre_675901470590545190", - "qualified_name": "benchmarkelementscollectorwriterpre_675901470590545190.BenchmarkElementsCollectorWriterPre", - "file_path": "publisher/htmlElementsCollector_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkRelatedMatchesIn", - "module_path": "github.com/gohugoio/hugo/related", - "import_alias": "benchmarkrelatedmatchesin_11634052282318476998", - "qualified_name": "benchmarkrelatedmatchesin_11634052282318476998.BenchmarkRelatedMatchesIn", - "file_path": "related/inverted_index_test.go", - "is_external": false - }, - { - "name": "BenchmarkRelatedNewIndex", - "module_path": "github.com/gohugoio/hugo/related", - "import_alias": "benchmarkrelatednewindex_11634052282318476998", - "qualified_name": "benchmarkrelatednewindex_11634052282318476998.BenchmarkRelatedNewIndex", - "file_path": "related/inverted_index_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkRelatedSite", - "module_path": "github.com/gohugoio/hugo/related", - "import_alias": "benchmarkrelatedsite_11634052282318476998", - "qualified_name": "benchmarkrelatedsite_11634052282318476998.BenchmarkRelatedSite", - "file_path": "related/related_integration_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHashImage", - "module_path": "github.com/gohugoio/hugo/resources", - "import_alias": "benchmarkhashimage_10958523510323494919", - "qualified_name": "benchmarkhashimage_10958523510323494919.BenchmarkHashImage", - "file_path": "resources/resource_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkImageExif", - "module_path": "github.com/gohugoio/hugo/resources", - "import_alias": "benchmarkimageexif_10958523510323494919", - "qualified_name": "benchmarkimageexif_10958523510323494919.BenchmarkImageExif", - "file_path": "resources/image_test.go", - "is_external": true - }, - { - "name": "BenchmarkResizeParallel", - "module_path": "github.com/gohugoio/hugo/resources", - "import_alias": "benchmarkresizeparallel_10958523510323494919", - "qualified_name": "benchmarkresizeparallel_10958523510323494919.BenchmarkResizeParallel", - "file_path": "resources/image_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkDecodeExif", - "module_path": "github.com/gohugoio/hugo/resources/images/exif", - "import_alias": "benchmarkdecodeexif_10346144041226160598", - "qualified_name": "benchmarkdecodeexif_10346144041226160598.BenchmarkDecodeExif", - "file_path": "resources/images/exif/exif_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkSummaryFromHTML", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarksummaryfromhtml_15519052165763528696", - "qualified_name": "benchmarksummaryfromhtml_15519052165763528696.BenchmarkSummaryFromHTML", - "file_path": "resources/page/page_markup_test.go", - "is_external": false - }, - { - "name": "BenchmarkSummaryFromHTMLWithDivider", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarksummaryfromhtmlwithdivider_15519052165763528696", - "qualified_name": "benchmarksummaryfromhtmlwithdivider_15519052165763528696.BenchmarkSummaryFromHTMLWithDivider", - "file_path": "resources/page/page_markup_test.go", - "is_external": false - }, - { - "name": "BenchmarkPageCache", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarkpagecache_15519052165763528696", - "qualified_name": "benchmarkpagecache_15519052165763528696.BenchmarkPageCache", - "file_path": "resources/page/pages_cache_test.go", - "is_external": false - }, - { - "name": "BenchmarkSearchPage", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarksearchpage_15519052165763528696", - "qualified_name": "benchmarksearchpage_15519052165763528696.BenchmarkSearchPage", - "file_path": "resources/page/pages_sort_search_test.go", - "is_external": false - }, - { - "name": "BenchmarkSortByWeightAndReverse", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarksortbyweightandreverse_15519052165763528696", - "qualified_name": "benchmarksortbyweightandreverse_15519052165763528696.BenchmarkSortByWeightAndReverse", - "file_path": "resources/page/pages_sort_test.go", - "is_external": false - }, - { - "name": "BenchmarkPermalinkExpand", - "module_path": "github.com/gohugoio/hugo/resources/page", - "import_alias": "benchmarkpermalinkexpand_15519052165763528696", - "qualified_name": "benchmarkpermalinkexpand_15519052165763528696.BenchmarkPermalinkExpand", - "file_path": "resources/page/permalinks_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkImportResolver", - "module_path": "github.com/gohugoio/hugo/resources/resource_transformers/cssjs", - "import_alias": "benchmarkimportresolver_1384745676888685941", - "qualified_name": "benchmarkimportresolver_1384745676888685941.BenchmarkImportResolver", - "file_path": "resources/resource_transformers/cssjs/inline_imports_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMerge", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkmerge_16168492887836003420", - "qualified_name": "benchmarkmerge_16168492887836003420.BenchmarkMerge", - "file_path": "tpl/collections/merge_test.go", - "is_external": false - }, - { - "name": "BenchmarkQuerify", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkquerify_16168492887836003420", - "qualified_name": "benchmarkquerify_16168492887836003420.BenchmarkQuerify", - "file_path": "tpl/collections/querify_test.go", - "is_external": false - }, - { - "name": "BenchmarkQuerifyMap", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkquerifymap_16168492887836003420", - "qualified_name": "benchmarkquerifymap_16168492887836003420.BenchmarkQuerifyMap", - "file_path": "tpl/collections/querify_test.go", - "is_external": false - }, - { - "name": "BenchmarkQuerifySlice", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkquerifyslice_16168492887836003420", - "qualified_name": "benchmarkquerifyslice_16168492887836003420.BenchmarkQuerifySlice", - "file_path": "tpl/collections/querify_test.go", - "is_external": false - }, - { - "name": "BenchmarkSortMap", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarksortmap_16168492887836003420", - "qualified_name": "benchmarksortmap_16168492887836003420.BenchmarkSortMap", - "file_path": "tpl/collections/sort_test.go", - "is_external": false - }, - { - "name": "BenchmarkWhereMap", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkwheremap_16168492887836003420", - "qualified_name": "benchmarkwheremap_16168492887836003420.BenchmarkWhereMap", - "file_path": "tpl/collections/where_test.go", - "is_external": false - }, - { - "name": "BenchmarkWhereOps", - "module_path": "github.com/gohugoio/hugo/tpl/collections", - "import_alias": "benchmarkwhereops_16168492887836003420", - "qualified_name": "benchmarkwhereops_16168492887836003420.BenchmarkWhereOps", - "file_path": "tpl/collections/where_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkXxHash", - "module_path": "github.com/gohugoio/hugo/tpl/hash", - "import_alias": "benchmarkxxhash_13921214352606506419", - "qualified_name": "benchmarkxxhash_13921214352606506419.BenchmarkXxHash", - "file_path": "tpl/hash/hash_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCSSEscaper", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkcssescaper_12483362044868267232", - "qualified_name": "benchmarkcssescaper_12483362044868267232.BenchmarkCSSEscaper", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkCSSEscaperNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkcssescapernospecials_12483362044868267232", - "qualified_name": "benchmarkcssescapernospecials_12483362044868267232.BenchmarkCSSEscaperNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkCSSValueFilter", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkcssvaluefilter_12483362044868267232", - "qualified_name": "benchmarkcssvaluefilter_12483362044868267232.BenchmarkCSSValueFilter", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkCSSValueFilterOk", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkcssvaluefilterok_12483362044868267232", - "qualified_name": "benchmarkcssvaluefilterok_12483362044868267232.BenchmarkCSSValueFilterOk", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkDecodeCSS", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkdecodecss_12483362044868267232", - "qualified_name": "benchmarkdecodecss_12483362044868267232.BenchmarkDecodeCSS", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkDecodeCSSNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkdecodecssnospecials_12483362044868267232", - "qualified_name": "benchmarkdecodecssnospecials_12483362044868267232.BenchmarkDecodeCSSNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/css_test.go", - "is_external": false - }, - { - "name": "BenchmarkEscapedExecute", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkescapedexecute_12483362044868267232", - "qualified_name": "benchmarkescapedexecute_12483362044868267232.BenchmarkEscapedExecute", - "file_path": "tpl/internal/go_templates/htmltemplate/escape_test.go", - "is_external": false - }, - { - "name": "BenchmarkHTMLNospaceEscaper", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkhtmlnospaceescaper_12483362044868267232", - "qualified_name": "benchmarkhtmlnospaceescaper_12483362044868267232.BenchmarkHTMLNospaceEscaper", - "file_path": "tpl/internal/go_templates/htmltemplate/html_test.go", - "is_external": false - }, - { - "name": "BenchmarkHTMLNospaceEscaperNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkhtmlnospaceescapernospecials_12483362044868267232", - "qualified_name": "benchmarkhtmlnospaceescapernospecials_12483362044868267232.BenchmarkHTMLNospaceEscaperNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/html_test.go", - "is_external": false - }, - { - "name": "BenchmarkStripTags", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkstriptags_12483362044868267232", - "qualified_name": "benchmarkstriptags_12483362044868267232.BenchmarkStripTags", - "file_path": "tpl/internal/go_templates/htmltemplate/html_test.go", - "is_external": false - }, - { - "name": "BenchmarkStripTagsNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkstriptagsnospecials_12483362044868267232", - "qualified_name": "benchmarkstriptagsnospecials_12483362044868267232.BenchmarkStripTagsNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/html_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSRegexpEscaper", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsregexpescaper_12483362044868267232", - "qualified_name": "benchmarkjsregexpescaper_12483362044868267232.BenchmarkJSRegexpEscaper", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSRegexpEscaperNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsregexpescapernospecials_12483362044868267232", - "qualified_name": "benchmarkjsregexpescapernospecials_12483362044868267232.BenchmarkJSRegexpEscaperNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSStrEscaper", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsstrescaper_12483362044868267232", - "qualified_name": "benchmarkjsstrescaper_12483362044868267232.BenchmarkJSStrEscaper", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSStrEscaperNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsstrescapernospecials_12483362044868267232", - "qualified_name": "benchmarkjsstrescapernospecials_12483362044868267232.BenchmarkJSStrEscaperNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSValEscaperWithNum", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsvalescaperwithnum_12483362044868267232", - "qualified_name": "benchmarkjsvalescaperwithnum_12483362044868267232.BenchmarkJSValEscaperWithNum", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSValEscaperWithObj", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsvalescaperwithobj_12483362044868267232", - "qualified_name": "benchmarkjsvalescaperwithobj_12483362044868267232.BenchmarkJSValEscaperWithObj", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSValEscaperWithObjNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsvalescaperwithobjnospecials_12483362044868267232", - "qualified_name": "benchmarkjsvalescaperwithobjnospecials_12483362044868267232.BenchmarkJSValEscaperWithObjNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSValEscaperWithStr", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsvalescaperwithstr_12483362044868267232", - "qualified_name": "benchmarkjsvalescaperwithstr_12483362044868267232.BenchmarkJSValEscaperWithStr", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkJSValEscaperWithStrNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkjsvalescaperwithstrnospecials_12483362044868267232", - "qualified_name": "benchmarkjsvalescaperwithstrnospecials_12483362044868267232.BenchmarkJSValEscaperWithStrNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/js_test.go", - "is_external": false - }, - { - "name": "BenchmarkTemplateSpecialTags", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarktemplatespecialtags_12483362044868267232", - "qualified_name": "benchmarktemplatespecialtags_12483362044868267232.BenchmarkTemplateSpecialTags", - "file_path": "tpl/internal/go_templates/htmltemplate/transition_test.go", - "is_external": false - }, - { - "name": "BenchmarkSrcsetFilter", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarksrcsetfilter_12483362044868267232", - "qualified_name": "benchmarksrcsetfilter_12483362044868267232.BenchmarkSrcsetFilter", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - }, - { - "name": "BenchmarkSrcsetFilterNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarksrcsetfilternospecials_12483362044868267232", - "qualified_name": "benchmarksrcsetfilternospecials_12483362044868267232.BenchmarkSrcsetFilterNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - }, - { - "name": "BenchmarkURLEscaper", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkurlescaper_12483362044868267232", - "qualified_name": "benchmarkurlescaper_12483362044868267232.BenchmarkURLEscaper", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - }, - { - "name": "BenchmarkURLEscaperNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkurlescapernospecials_12483362044868267232", - "qualified_name": "benchmarkurlescapernospecials_12483362044868267232.BenchmarkURLEscaperNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - }, - { - "name": "BenchmarkURLNormalizer", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkurlnormalizer_12483362044868267232", - "qualified_name": "benchmarkurlnormalizer_12483362044868267232.BenchmarkURLNormalizer", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - }, - { - "name": "BenchmarkURLNormalizerNoSpecials", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate", - "import_alias": "benchmarkurlnormalizernospecials_12483362044868267232", - "qualified_name": "benchmarkurlnormalizernospecials_12483362044868267232.BenchmarkURLNormalizerNoSpecials", - "file_path": "tpl/internal/go_templates/htmltemplate/url_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkListString", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse", - "import_alias": "benchmarkliststring_12091539013657696344", - "qualified_name": "benchmarkliststring_12091539013657696344.BenchmarkListString", - "file_path": "tpl/internal/go_templates/texttemplate/parse/parse_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseLarge", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse", - "import_alias": "benchmarkparselarge_12091539013657696344", - "qualified_name": "benchmarkparselarge_12091539013657696344.BenchmarkParseLarge", - "file_path": "tpl/internal/go_templates/texttemplate/parse/parse_test.go", - "is_external": false - }, - { - "name": "BenchmarkVariableString", - "module_path": "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse", - "import_alias": "benchmarkvariablestring_12091539013657696344", - "qualified_name": "benchmarkvariablestring_12091539013657696344.BenchmarkVariableString", - "file_path": "tpl/internal/go_templates/texttemplate/parse/parse_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkIncludeCached", - "module_path": "github.com/gohugoio/hugo/tpl/partials", - "import_alias": "benchmarkincludecached_1423468059592503472", - "qualified_name": "benchmarkincludecached_1423468059592503472.BenchmarkIncludeCached", - "file_path": "tpl/partials/partials_integration_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTruncate", - "module_path": "github.com/gohugoio/hugo/tpl/strings", - "import_alias": "benchmarktruncate_11257671554297370755", - "qualified_name": "benchmarktruncate_11257671554297370755.BenchmarkTruncate", - "file_path": "tpl/strings/truncate_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkInWithCaching", - "module_path": "github.com/gohugoio/hugo/tpl/time", - "import_alias": "benchmarkinwithcaching_2240231418426689527", - "qualified_name": "benchmarkinwithcaching_2240231418426689527.BenchmarkInWithCaching", - "file_path": "tpl/time/time_test.go", - "is_external": true - }, - { - "name": "BenchmarkInWithoutCaching", - "module_path": "github.com/gohugoio/hugo/tpl/time", - "import_alias": "benchmarkinwithoutcaching_2240231418426689527", - "qualified_name": "benchmarkinwithoutcaching_2240231418426689527.BenchmarkInWithoutCaching", - "file_path": "tpl/time/time_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkCompareDescriptors", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarkcomparedescriptors_16591105017139932943", - "qualified_name": "benchmarkcomparedescriptors_16591105017139932943.BenchmarkCompareDescriptors", - "file_path": "tpl/tplimpl/templatedescriptor_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExecuteWithContext", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarkexecutewithcontext_16591105017139932943", - "qualified_name": "benchmarkexecutewithcontext_16591105017139932943.BenchmarkExecuteWithContext", - "file_path": "tpl/tplimpl/templatestore_integration_test.go", - "is_external": true - }, - { - "name": "BenchmarkLookupPagesLayout", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarklookuppageslayout_16591105017139932943", - "qualified_name": "benchmarklookuppageslayout_16591105017139932943.BenchmarkLookupPagesLayout", - "file_path": "tpl/tplimpl/templatestore_integration_test.go", - "is_external": true - }, - { - "name": "BenchmarkLookupPartial", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarklookuppartial_16591105017139932943", - "qualified_name": "benchmarklookuppartial_16591105017139932943.BenchmarkLookupPartial", - "file_path": "tpl/tplimpl/templatestore_integration_test.go", - "is_external": true - }, - { - "name": "BenchmarkLookupShortcode", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarklookupshortcode_16591105017139932943", - "qualified_name": "benchmarklookupshortcode_16591105017139932943.BenchmarkLookupShortcode", - "file_path": "tpl/tplimpl/templatestore_integration_test.go", - "is_external": true - }, - { - "name": "BenchmarkNewTemplateStore", - "module_path": "github.com/gohugoio/hugo/tpl/tplimpl", - "import_alias": "benchmarknewtemplatestore_16591105017139932943", - "qualified_name": "benchmarknewtemplatestore_16591105017139932943.BenchmarkNewTemplateStore", - "file_path": "tpl/tplimpl/templatestore_integration_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkUnmarshalResource", - "module_path": "github.com/gohugoio/hugo/tpl/transform", - "import_alias": "benchmarkunmarshalresource_16334178898995765701", - "qualified_name": "benchmarkunmarshalresource_16334178898995765701.BenchmarkUnmarshalResource", - "file_path": "tpl/transform/unmarshal_test.go", - "is_external": true - }, - { - "name": "BenchmarkUnmarshalString", - "module_path": "github.com/gohugoio/hugo/tpl/transform", - "import_alias": "benchmarkunmarshalstring_16334178898995765701", - "qualified_name": "benchmarkunmarshalstring_16334178898995765701.BenchmarkUnmarshalString", - "file_path": "tpl/transform/unmarshal_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkLiveReloadInject", - "module_path": "github.com/gohugoio/hugo/transform/livereloadinject", - "import_alias": "benchmarklivereloadinject_13224044352763152379", - "qualified_name": "benchmarklivereloadinject_13224044352763152379.BenchmarkLiveReloadInject", - "file_path": "transform/livereloadinject/livereloadinject_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAbsURL", - "module_path": "github.com/gohugoio/hugo/transform/urlreplacers", - "import_alias": "benchmarkabsurl_3155915875871903319", - "qualified_name": "benchmarkabsurl_3155915875871903319.BenchmarkAbsURL", - "file_path": "transform/urlreplacers/absurlreplacer_test.go", - "is_external": false - }, - { - "name": "BenchmarkAbsURLSrcset", - "module_path": "github.com/gohugoio/hugo/transform/urlreplacers", - "import_alias": "benchmarkabsurlsrcset_3155915875871903319", - "qualified_name": "benchmarkabsurlsrcset_3155915875871903319.BenchmarkAbsURLSrcset", - "file_path": "transform/urlreplacers/absurlreplacer_test.go", - "is_external": false - }, - { - "name": "BenchmarkXMLAbsURL", - "module_path": "github.com/gohugoio/hugo/transform/urlreplacers", - "import_alias": "benchmarkxmlabsurl_3155915875871903319", - "qualified_name": "benchmarkxmlabsurl_3155915875871903319.BenchmarkXMLAbsURL", - "file_path": "transform/urlreplacers/absurlreplacer_test.go", - "is_external": false - }, - { - "name": "BenchmarkXMLAbsURLSrcset", - "module_path": "github.com/gohugoio/hugo/transform/urlreplacers", - "import_alias": "benchmarkxmlabsurlsrcset_3155915875871903319", - "qualified_name": "benchmarkxmlabsurlsrcset_3155915875871903319.BenchmarkXMLAbsURLSrcset", - "file_path": "transform/urlreplacers/absurlreplacer_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkPoller", - "module_path": "github.com/gohugoio/hugo/watcher/filenotify", - "import_alias": "benchmarkpoller_5517665682261906176", - "qualified_name": "benchmarkpoller_5517665682261906176.BenchmarkPoller", - "file_path": "watcher/filenotify/poller_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__common__htime.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__common__htime.snap deleted file mode 100644 index dd963fca..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__common__htime.snap +++ /dev/null @@ -1,60 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "htime", - "ImportPath": "github.com/gohugoio/hugo/common/htime [github.com/gohugoio/hugo/common/htime.test]", - "GoFiles": [ - "time.go", - "time_test.go" - ], - "TestGoFiles": [ - "time_test.go" - ], - "Imports": [ - "github.com/frankban/quicktest", - "github.com/gohugoio/localescompressed", - "testing", - "time", - "github.com/bep/clocks", - "github.com/gohugoio/locales", - "github.com/spf13/cast", - "log", - "strings", - "time" - ], - "TestImports": [ - "github.com/frankban/quicktest", - "github.com/gohugoio/localescompressed", - "testing", - "time" - ], - "CompiledGoFiles": [ - "time.go", - "time_test.go" - ], - "ForTest": "github.com/gohugoio/hugo/common/htime", - "Module": { - "Path": "github.com/gohugoio/hugo", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.24", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkTimeFormatter", - "module_path": "github.com/gohugoio/hugo/common/htime", - "import_alias": "benchmarktimeformatter_6847590086467670113", - "qualified_name": "benchmarktimeformatter_6847590086467670113.BenchmarkTimeFormatter", - "file_path": "common/htime/time_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__identity.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__identity.snap deleted file mode 100644 index ae5354c6..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@hugo__identity.snap +++ /dev/null @@ -1,64 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": { - "Dir": "[package_dir]", - "Name": "identity_test", - "ImportPath": "github.com/gohugoio/hugo/identity_test [github.com/gohugoio/hugo/identity.test]", - "GoFiles": [ - "finder_test.go", - "identity_test.go" - ], - "TestGoFiles": null, - "Imports": [ - "fmt", - "github.com/frankban/quicktest", - "github.com/gohugoio/hugo/identity [github.com/gohugoio/hugo/identity.test]", - "github.com/gohugoio/hugo/identity/identitytesting [github.com/gohugoio/hugo/identity.test]", - "testing" - ], - "TestImports": null, - "CompiledGoFiles": [ - "finder_test.go", - "identity_test.go" - ], - "ForTest": "github.com/gohugoio/hugo/identity", - "Module": { - "Path": "github.com/gohugoio/hugo", - "Dir": "[module_dir]", - "GoMod": "[go_mod_path]", - "GoVersion": "1.24", - "Main": true - } - }, - "benchmarks": [ - { - "name": "BenchmarkFinder", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkfinder_12445121846465317058", - "qualified_name": "benchmarkfinder_12445121846465317058.BenchmarkFinder", - "file_path": "identity/finder_test.go", - "is_external": true - }, - { - "name": "BenchmarkIdentityManager", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkidentitymanager_12445121846465317058", - "qualified_name": "benchmarkidentitymanager_12445121846465317058.BenchmarkIdentityManager", - "file_path": "identity/identity_test.go", - "is_external": true - }, - { - "name": "BenchmarkIsNotDependent", - "module_path": "github.com/gohugoio/hugo/identity", - "import_alias": "benchmarkisnotdependent_12445121846465317058", - "qualified_name": "benchmarkisnotdependent_12445121846465317058.BenchmarkIsNotDependent", - "file_path": "identity/identity_test.go", - "is_external": true - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@opentelemetry-go.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@opentelemetry-go.snap deleted file mode 100644 index aaa5d298..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@opentelemetry-go.snap +++ /dev/null @@ -1,247 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBool", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkbool_9112764275935889827", - "qualified_name": "benchmarkbool_9112764275935889827.BenchmarkBool", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkBoolSlice", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkboolslice_9112764275935889827", - "qualified_name": "benchmarkboolslice_9112764275935889827.BenchmarkBoolSlice", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkEquivalentMapAccess", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkequivalentmapaccess_9112764275935889827", - "qualified_name": "benchmarkequivalentmapaccess_9112764275935889827.BenchmarkEquivalentMapAccess", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkFloat64", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkfloat64_9112764275935889827", - "qualified_name": "benchmarkfloat64_9112764275935889827.BenchmarkFloat64", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkFloat64Slice", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkfloat64slice_9112764275935889827", - "qualified_name": "benchmarkfloat64slice_9112764275935889827.BenchmarkFloat64Slice", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkInt", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkint_9112764275935889827", - "qualified_name": "benchmarkint_9112764275935889827.BenchmarkInt", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkInt64", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkint64_9112764275935889827", - "qualified_name": "benchmarkint64_9112764275935889827.BenchmarkInt64", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkInt64Slice", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkint64slice_9112764275935889827", - "qualified_name": "benchmarkint64slice_9112764275935889827.BenchmarkInt64Slice", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkIntSlice", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkintslice_9112764275935889827", - "qualified_name": "benchmarkintslice_9112764275935889827.BenchmarkIntSlice", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkString", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkstring_9112764275935889827", - "qualified_name": "benchmarkstring_9112764275935889827.BenchmarkString", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkStringSlice", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkstringslice_9112764275935889827", - "qualified_name": "benchmarkstringslice_9112764275935889827.BenchmarkStringSlice", - "file_path": "attribute/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkFiltering", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarkfiltering_9112764275935889827", - "qualified_name": "benchmarkfiltering_9112764275935889827.BenchmarkFiltering", - "file_path": "attribute/set_test.go", - "is_external": true - }, - { - "name": "BenchmarkNewSet", - "module_path": "go.opentelemetry.io/otel/attribute", - "import_alias": "benchmarknewset_9112764275935889827", - "qualified_name": "benchmarknewset_9112764275935889827.BenchmarkNewSet", - "file_path": "attribute/set_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAsFloat64Slice", - "module_path": "go.opentelemetry.io/otel/attribute/internal", - "import_alias": "benchmarkasfloat64slice_4292079508431374558", - "qualified_name": "benchmarkasfloat64slice_4292079508431374558.BenchmarkAsFloat64Slice", - "file_path": "attribute/internal/attribute_test.go", - "is_external": false - }, - { - "name": "BenchmarkBoolSliceValue", - "module_path": "go.opentelemetry.io/otel/attribute/internal", - "import_alias": "benchmarkboolslicevalue_4292079508431374558", - "qualified_name": "benchmarkboolslicevalue_4292079508431374558.BenchmarkBoolSliceValue", - "file_path": "attribute/internal/attribute_test.go", - "is_external": false - }, - { - "name": "BenchmarkFloat64SliceValue", - "module_path": "go.opentelemetry.io/otel/attribute/internal", - "import_alias": "benchmarkfloat64slicevalue_4292079508431374558", - "qualified_name": "benchmarkfloat64slicevalue_4292079508431374558.BenchmarkFloat64SliceValue", - "file_path": "attribute/internal/attribute_test.go", - "is_external": false - }, - { - "name": "BenchmarkInt64SliceValue", - "module_path": "go.opentelemetry.io/otel/attribute/internal", - "import_alias": "benchmarkint64slicevalue_4292079508431374558", - "qualified_name": "benchmarkint64slicevalue_4292079508431374558.BenchmarkInt64SliceValue", - "file_path": "attribute/internal/attribute_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringSliceValue", - "module_path": "go.opentelemetry.io/otel/attribute/internal", - "import_alias": "benchmarkstringslicevalue_4292079508431374558", - "qualified_name": "benchmarkstringslicevalue_4292079508431374558.BenchmarkStringSliceValue", - "file_path": "attribute/internal/attribute_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkMemberString", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarkmemberstring_16804148212268947688", - "qualified_name": "benchmarkmemberstring_16804148212268947688.BenchmarkMemberString", - "file_path": "baggage/baggage_test.go", - "is_external": false - }, - { - "name": "BenchmarkNew", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarknew_16804148212268947688", - "qualified_name": "benchmarknew_16804148212268947688.BenchmarkNew", - "file_path": "baggage/baggage_test.go", - "is_external": false - }, - { - "name": "BenchmarkNewMemberRaw", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarknewmemberraw_16804148212268947688", - "qualified_name": "benchmarknewmemberraw_16804148212268947688.BenchmarkNewMemberRaw", - "file_path": "baggage/baggage_test.go", - "is_external": false - }, - { - "name": "BenchmarkParse", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarkparse_16804148212268947688", - "qualified_name": "benchmarkparse_16804148212268947688.BenchmarkParse", - "file_path": "baggage/baggage_test.go", - "is_external": false - }, - { - "name": "BenchmarkString", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarkstring_16804148212268947688", - "qualified_name": "benchmarkstring_16804148212268947688.BenchmarkString", - "file_path": "baggage/baggage_test.go", - "is_external": false - }, - { - "name": "BenchmarkValueEscape", - "module_path": "go.opentelemetry.io/otel/baggage", - "import_alias": "benchmarkvalueescape_16804148212268947688", - "qualified_name": "benchmarkvalueescape_16804148212268947688.BenchmarkValueEscape", - "file_path": "baggage/baggage_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkStartEndSpanNoSDK", - "module_path": "go.opentelemetry.io/otel/internal/global", - "import_alias": "benchmarkstartendspannosdk_11952587464289651052", - "qualified_name": "benchmarkstartendspannosdk_11952587464289651052.BenchmarkStartEndSpanNoSDK", - "file_path": "internal/global/benchmark_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkExtract", - "module_path": "go.opentelemetry.io/otel/propagation", - "import_alias": "benchmarkextract_15994792647402085651", - "qualified_name": "benchmarkextract_15994792647402085651.BenchmarkExtract", - "file_path": "propagation/trace_context_benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkInject", - "module_path": "go.opentelemetry.io/otel/propagation", - "import_alias": "benchmarkinject_15994792647402085651", - "qualified_name": "benchmarkinject_15994792647402085651.BenchmarkInject", - "file_path": "propagation/trace_context_benchmark_test.go", - "is_external": true - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@quic-go.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@quic-go.snap deleted file mode 100644 index 32e7c527..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@quic-go.snap +++ /dev/null @@ -1,381 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkConnIDManagerInOrder", - "module_path": "github.com/quic-go/quic-go", - "import_alias": "benchmarkconnidmanagerinorder_17725812368620695335", - "qualified_name": "benchmarkconnidmanagerinorder_17725812368620695335.BenchmarkConnIDManagerInOrder", - "file_path": "conn_id_manager_test.go", - "is_external": false - }, - { - "name": "BenchmarkConnIDManagerReordered", - "module_path": "github.com/quic-go/quic-go", - "import_alias": "benchmarkconnidmanagerreordered_17725812368620695335", - "qualified_name": "benchmarkconnidmanagerreordered_17725812368620695335.BenchmarkConnIDManagerReordered", - "file_path": "conn_id_manager_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHandshake", - "module_path": "github.com/quic-go/quic-go/integrationtests/self", - "import_alias": "benchmarkhandshake_2479404715441424897", - "qualified_name": "benchmarkhandshake_2479404715441424897.BenchmarkHandshake", - "file_path": "integrationtests/self/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkStreamChurn", - "module_path": "github.com/quic-go/quic-go/integrationtests/self", - "import_alias": "benchmarkstreamchurn_2479404715441424897", - "qualified_name": "benchmarkstreamchurn_2479404715441424897.BenchmarkStreamChurn", - "file_path": "integrationtests/self/benchmark_test.go", - "is_external": true - }, - { - "name": "BenchmarkTransfer", - "module_path": "github.com/quic-go/quic-go/integrationtests/self", - "import_alias": "benchmarktransfer_2479404715441424897", - "qualified_name": "benchmarktransfer_2479404715441424897.BenchmarkTransfer", - "file_path": "integrationtests/self/benchmark_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHistoryIsDuplicate", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarkhistoryisduplicate_9929565287867201488", - "qualified_name": "benchmarkhistoryisduplicate_9929565287867201488.BenchmarkHistoryIsDuplicate", - "file_path": "internal/ackhandler/received_packet_history_test.go", - "is_external": false - }, - { - "name": "BenchmarkHistoryReceiveCommonCase", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarkhistoryreceivecommoncase_9929565287867201488", - "qualified_name": "benchmarkhistoryreceivecommoncase_9929565287867201488.BenchmarkHistoryReceiveCommonCase", - "file_path": "internal/ackhandler/received_packet_history_test.go", - "is_external": false - }, - { - "name": "BenchmarkHistoryReceiveReversePacketsWithGaps", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarkhistoryreceivereversepacketswithgaps_9929565287867201488", - "qualified_name": "benchmarkhistoryreceivereversepacketswithgaps_9929565287867201488.BenchmarkHistoryReceiveReversePacketsWithGaps", - "file_path": "internal/ackhandler/received_packet_history_test.go", - "is_external": false - }, - { - "name": "BenchmarkHistoryReceiveSequentialPackets", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarkhistoryreceivesequentialpackets_9929565287867201488", - "qualified_name": "benchmarkhistoryreceivesequentialpackets_9929565287867201488.BenchmarkHistoryReceiveSequentialPackets", - "file_path": "internal/ackhandler/received_packet_history_test.go", - "is_external": false - }, - { - "name": "BenchmarkHistoryReceiveSequentialPacketsWithGaps", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarkhistoryreceivesequentialpacketswithgaps_9929565287867201488", - "qualified_name": "benchmarkhistoryreceivesequentialpacketswithgaps_9929565287867201488.BenchmarkHistoryReceiveSequentialPacketsWithGaps", - "file_path": "internal/ackhandler/received_packet_history_test.go", - "is_external": false - }, - { - "name": "BenchmarkSendAndAcknowledge", - "module_path": "github.com/quic-go/quic-go/internal/ackhandler", - "import_alias": "benchmarksendandacknowledge_9929565287867201488", - "qualified_name": "benchmarksendandacknowledge_9929565287867201488.BenchmarkSendAndAcknowledge", - "file_path": "internal/ackhandler/sent_packet_handler_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkPacer", - "module_path": "github.com/quic-go/quic-go/internal/congestion", - "import_alias": "benchmarkpacer_14226698885780729378", - "qualified_name": "benchmarkpacer_14226698885780729378.BenchmarkPacer", - "file_path": "internal/congestion/pacer_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkHKDFExpandLabelOurs", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkhkdfexpandlabelours_3445167521795741151", - "qualified_name": "benchmarkhkdfexpandlabelours_3445167521795741151.BenchmarkHKDFExpandLabelOurs", - "file_path": "internal/handshake/hkdf_test.go", - "is_external": false - }, - { - "name": "BenchmarkHKDFExpandLabelStandardLibrary", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkhkdfexpandlabelstandardlibrary_3445167521795741151", - "qualified_name": "benchmarkhkdfexpandlabelstandardlibrary_3445167521795741151.BenchmarkHKDFExpandLabelStandardLibrary", - "file_path": "internal/handshake/hkdf_test.go", - "is_external": false - }, - { - "name": "BenchmarkInitialAEAD", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkinitialaead_3445167521795741151", - "qualified_name": "benchmarkinitialaead_3445167521795741151.BenchmarkInitialAEAD", - "file_path": "internal/handshake/initial_aead_test.go", - "is_external": false - }, - { - "name": "BenchmarkInitialAEADCreate", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkinitialaeadcreate_3445167521795741151", - "qualified_name": "benchmarkinitialaeadcreate_3445167521795741151.BenchmarkInitialAEADCreate", - "file_path": "internal/handshake/initial_aead_test.go", - "is_external": false - }, - { - "name": "BenchmarkPacketDecryption", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkpacketdecryption_3445167521795741151", - "qualified_name": "benchmarkpacketdecryption_3445167521795741151.BenchmarkPacketDecryption", - "file_path": "internal/handshake/updatable_aead_test.go", - "is_external": false - }, - { - "name": "BenchmarkPacketEncryption", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkpacketencryption_3445167521795741151", - "qualified_name": "benchmarkpacketencryption_3445167521795741151.BenchmarkPacketEncryption", - "file_path": "internal/handshake/updatable_aead_test.go", - "is_external": false - }, - { - "name": "BenchmarkRollKeys", - "module_path": "github.com/quic-go/quic-go/internal/handshake", - "import_alias": "benchmarkrollkeys_3445167521795741151", - "qualified_name": "benchmarkrollkeys_3445167521795741151.BenchmarkRollKeys", - "file_path": "internal/handshake/updatable_aead_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkNow", - "module_path": "github.com/quic-go/quic-go/internal/monotime", - "import_alias": "benchmarknow_6421836119628624696", - "qualified_name": "benchmarknow_6421836119628624696.BenchmarkNow", - "file_path": "internal/monotime/time_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkConnectionIDStringer", - "module_path": "github.com/quic-go/quic-go/internal/protocol", - "import_alias": "benchmarkconnectionidstringer_3895154521026762770", - "qualified_name": "benchmarkconnectionidstringer_3895154521026762770.BenchmarkConnectionIDStringer", - "file_path": "internal/protocol/connection_id_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkRingBuffer", - "module_path": "github.com/quic-go/quic-go/internal/utils/ringbuffer", - "import_alias": "benchmarkringbuffer_14300724861336105258", - "qualified_name": "benchmarkringbuffer_14300724861336105258.BenchmarkRingBuffer", - "file_path": "internal/utils/ringbuffer/ringbuffer_bench_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkParseExtendedHeader", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparseextendedheader_7372446328961579375", - "qualified_name": "benchmarkparseextendedheader_7372446328961579375.BenchmarkParseExtendedHeader", - "file_path": "internal/wire/extended_header_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseAckFrame", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparseackframe_7372446328961579375", - "qualified_name": "benchmarkparseackframe_7372446328961579375.BenchmarkParseAckFrame", - "file_path": "internal/wire/frame_parser_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseDatagramFrame", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparsedatagramframe_7372446328961579375", - "qualified_name": "benchmarkparsedatagramframe_7372446328961579375.BenchmarkParseDatagramFrame", - "file_path": "internal/wire/frame_parser_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseOtherFrames", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparseotherframes_7372446328961579375", - "qualified_name": "benchmarkparseotherframes_7372446328961579375.BenchmarkParseOtherFrames", - "file_path": "internal/wire/frame_parser_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseStreamFrame", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparsestreamframe_7372446328961579375", - "qualified_name": "benchmarkparsestreamframe_7372446328961579375.BenchmarkParseStreamFrame", - "file_path": "internal/wire/frame_parser_test.go", - "is_external": false - }, - { - "name": "BenchmarkArbitraryHeaderParsing", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkarbitraryheaderparsing_7372446328961579375", - "qualified_name": "benchmarkarbitraryheaderparsing_7372446328961579375.BenchmarkArbitraryHeaderParsing", - "file_path": "internal/wire/header_test.go", - "is_external": false - }, - { - "name": "BenchmarkIs0RTTPacket", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkis0rttpacket_7372446328961579375", - "qualified_name": "benchmarkis0rttpacket_7372446328961579375.BenchmarkIs0RTTPacket", - "file_path": "internal/wire/header_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseInitial", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparseinitial_7372446328961579375", - "qualified_name": "benchmarkparseinitial_7372446328961579375.BenchmarkParseInitial", - "file_path": "internal/wire/header_test.go", - "is_external": false - }, - { - "name": "BenchmarkParseRetry", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkparseretry_7372446328961579375", - "qualified_name": "benchmarkparseretry_7372446328961579375.BenchmarkParseRetry", - "file_path": "internal/wire/header_test.go", - "is_external": false - }, - { - "name": "BenchmarkWriteShortHeader", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkwriteshortheader_7372446328961579375", - "qualified_name": "benchmarkwriteshortheader_7372446328961579375.BenchmarkWriteShortHeader", - "file_path": "internal/wire/short_header_test.go", - "is_external": false - }, - { - "name": "BenchmarkTransportParameters", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarktransportparameters_7372446328961579375", - "qualified_name": "benchmarktransportparameters_7372446328961579375.BenchmarkTransportParameters", - "file_path": "internal/wire/transport_parameter_test.go", - "is_external": false - }, - { - "name": "BenchmarkComposeVersionNegotiationPacket", - "module_path": "github.com/quic-go/quic-go/internal/wire", - "import_alias": "benchmarkcomposeversionnegotiationpacket_7372446328961579375", - "qualified_name": "benchmarkcomposeversionnegotiationpacket_7372446328961579375.BenchmarkComposeVersionNegotiationPacket", - "file_path": "internal/wire/version_negotiation_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkConnectionTracing", - "module_path": "github.com/quic-go/quic-go/qlog", - "import_alias": "benchmarkconnectiontracing_9904566609006801914", - "qualified_name": "benchmarkconnectiontracing_9904566609006801914.BenchmarkConnectionTracing", - "file_path": "qlog/benchmark_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAppend", - "module_path": "github.com/quic-go/quic-go/quicvarint", - "import_alias": "benchmarkappend_17354483699754972331", - "qualified_name": "benchmarkappend_17354483699754972331.BenchmarkAppend", - "file_path": "quicvarint/varint_test.go", - "is_external": false - }, - { - "name": "BenchmarkAppendWithLen", - "module_path": "github.com/quic-go/quic-go/quicvarint", - "import_alias": "benchmarkappendwithlen_17354483699754972331", - "qualified_name": "benchmarkappendwithlen_17354483699754972331.BenchmarkAppendWithLen", - "file_path": "quicvarint/varint_test.go", - "is_external": false - }, - { - "name": "BenchmarkParse", - "module_path": "github.com/quic-go/quic-go/quicvarint", - "import_alias": "benchmarkparse_17354483699754972331", - "qualified_name": "benchmarkparse_17354483699754972331.BenchmarkParse", - "file_path": "quicvarint/varint_test.go", - "is_external": false - }, - { - "name": "BenchmarkReadBytesReader", - "module_path": "github.com/quic-go/quic-go/quicvarint", - "import_alias": "benchmarkreadbytesreader_17354483699754972331", - "qualified_name": "benchmarkreadbytesreader_17354483699754972331.BenchmarkReadBytesReader", - "file_path": "quicvarint/varint_test.go", - "is_external": false - }, - { - "name": "BenchmarkReadSimpleReader", - "module_path": "github.com/quic-go/quic-go/quicvarint", - "import_alias": "benchmarkreadsimplereader_17354483699754972331", - "qualified_name": "benchmarkreadsimplereader_17354483699754972331.BenchmarkReadSimpleReader", - "file_path": "quicvarint/varint_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zap.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zap.snap deleted file mode 100644 index 73a76c38..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zap.snap +++ /dev/null @@ -1,372 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBoolsArrayMarshaler", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkboolsarraymarshaler_8965155587179714226", - "qualified_name": "benchmarkboolsarraymarshaler_8965155587179714226.BenchmarkBoolsArrayMarshaler", - "file_path": "array_test.go", - "is_external": false - }, - { - "name": "BenchmarkBoolsReflect", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkboolsreflect_8965155587179714226", - "qualified_name": "benchmarkboolsreflect_8965155587179714226.BenchmarkBoolsReflect", - "file_path": "array_test.go", - "is_external": false - }, - { - "name": "Benchmark100Fields", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark100fields_8965155587179714226", - "qualified_name": "benchmark100fields_8965155587179714226.Benchmark100Fields", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "Benchmark10Fields", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark10fields_8965155587179714226", - "qualified_name": "benchmark10fields_8965155587179714226.Benchmark10Fields", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "Benchmark5WithLazysNotUsed", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark5withlazysnotused_8965155587179714226", - "qualified_name": "benchmark5withlazysnotused_8965155587179714226.Benchmark5WithLazysNotUsed", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "Benchmark5WithLazysUsed", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark5withlazysused_8965155587179714226", - "qualified_name": "benchmark5withlazysused_8965155587179714226.Benchmark5WithLazysUsed", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "Benchmark5WithsNotUsed", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark5withsnotused_8965155587179714226", - "qualified_name": "benchmark5withsnotused_8965155587179714226.Benchmark5WithsNotUsed", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "Benchmark5WithsUsed", - "module_path": "go.uber.org/zap", - "import_alias": "benchmark5withsused_8965155587179714226", - "qualified_name": "benchmark5withsused_8965155587179714226.Benchmark5WithsUsed", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkAddCallerAndStacktrace", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkaddcallerandstacktrace_8965155587179714226", - "qualified_name": "benchmarkaddcallerandstacktrace_8965155587179714226.BenchmarkAddCallerAndStacktrace", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkAddCallerHook", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkaddcallerhook_8965155587179714226", - "qualified_name": "benchmarkaddcallerhook_8965155587179714226.BenchmarkAddCallerHook", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkAny", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkany_8965155587179714226", - "qualified_name": "benchmarkany_8965155587179714226.BenchmarkAny", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkBoolField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkboolfield_8965155587179714226", - "qualified_name": "benchmarkboolfield_8965155587179714226.BenchmarkBoolField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkByteStringField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkbytestringfield_8965155587179714226", - "qualified_name": "benchmarkbytestringfield_8965155587179714226.BenchmarkByteStringField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkDurationField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkdurationfield_8965155587179714226", - "qualified_name": "benchmarkdurationfield_8965155587179714226.BenchmarkDurationField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkErrorField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkerrorfield_8965155587179714226", - "qualified_name": "benchmarkerrorfield_8965155587179714226.BenchmarkErrorField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkErrorsField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkerrorsfield_8965155587179714226", - "qualified_name": "benchmarkerrorsfield_8965155587179714226.BenchmarkErrorsField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkFloat64Field", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkfloat64field_8965155587179714226", - "qualified_name": "benchmarkfloat64field_8965155587179714226.BenchmarkFloat64Field", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkInt64Field", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkint64field_8965155587179714226", - "qualified_name": "benchmarkint64field_8965155587179714226.BenchmarkInt64Field", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkIntField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkintfield_8965155587179714226", - "qualified_name": "benchmarkintfield_8965155587179714226.BenchmarkIntField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkNoContext", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarknocontext_8965155587179714226", - "qualified_name": "benchmarknocontext_8965155587179714226.BenchmarkNoContext", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkObjectField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkobjectfield_8965155587179714226", - "qualified_name": "benchmarkobjectfield_8965155587179714226.BenchmarkObjectField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkReflectField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkreflectfield_8965155587179714226", - "qualified_name": "benchmarkreflectfield_8965155587179714226.BenchmarkReflectField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkStackField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkstackfield_8965155587179714226", - "qualified_name": "benchmarkstackfield_8965155587179714226.BenchmarkStackField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkstringfield_8965155587179714226", - "qualified_name": "benchmarkstringfield_8965155587179714226.BenchmarkStringField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkStringerField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarkstringerfield_8965155587179714226", - "qualified_name": "benchmarkstringerfield_8965155587179714226.BenchmarkStringerField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkTimeField", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarktimefield_8965155587179714226", - "qualified_name": "benchmarktimefield_8965155587179714226.BenchmarkTimeField", - "file_path": "logger_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkLnSugarSingleStrArg", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarklnsugarsinglestrarg_8965155587179714226", - "qualified_name": "benchmarklnsugarsinglestrarg_8965155587179714226.BenchmarkLnSugarSingleStrArg", - "file_path": "sugar_test.go", - "is_external": false - }, - { - "name": "BenchmarkSugarSingleStrArg", - "module_path": "go.uber.org/zap", - "import_alias": "benchmarksugarsinglestrarg_8965155587179714226", - "qualified_name": "benchmarksugarsinglestrarg_8965155587179714226.BenchmarkSugarSingleStrArg", - "file_path": "sugar_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBuffers", - "module_path": "go.uber.org/zap/buffer", - "import_alias": "benchmarkbuffers_11185874187691884622", - "qualified_name": "benchmarkbuffers_11185874187691884622.BenchmarkBuffers", - "file_path": "buffer/buffer_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkTake", - "module_path": "go.uber.org/zap/internal/stacktrace", - "import_alias": "benchmarktake_1125362636766148011", - "qualified_name": "benchmarktake_1125362636766148011.BenchmarkTake", - "file_path": "internal/stacktrace/stack_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkBufferedWriteSyncer", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkbufferedwritesyncer_9756807534644178564", - "qualified_name": "benchmarkbufferedwritesyncer_9756807534644178564.BenchmarkBufferedWriteSyncer", - "file_path": "zapcore/buffered_write_syncer_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkMultiWriteSyncer", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkmultiwritesyncer_9756807534644178564", - "qualified_name": "benchmarkmultiwritesyncer_9756807534644178564.BenchmarkMultiWriteSyncer", - "file_path": "zapcore/write_syncer_bench_test.go", - "is_external": false - }, - { - "name": "BenchmarkWriteSyncer", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkwritesyncer_9756807534644178564", - "qualified_name": "benchmarkwritesyncer_9756807534644178564.BenchmarkWriteSyncer", - "file_path": "zapcore/write_syncer_bench_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkZapConsole", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkzapconsole_9756807534644178564", - "qualified_name": "benchmarkzapconsole_9756807534644178564.BenchmarkZapConsole", - "file_path": "zapcore/console_encoder_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkJSONLogMarshalerFunc", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkjsonlogmarshalerfunc_9756807534644178564", - "qualified_name": "benchmarkjsonlogmarshalerfunc_9756807534644178564.BenchmarkJSONLogMarshalerFunc", - "file_path": "zapcore/json_encoder_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkStandardJSON", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkstandardjson_9756807534644178564", - "qualified_name": "benchmarkstandardjson_9756807534644178564.BenchmarkStandardJSON", - "file_path": "zapcore/json_encoder_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkZapJSON", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkzapjson_9756807534644178564", - "qualified_name": "benchmarkzapjson_9756807534644178564.BenchmarkZapJSON", - "file_path": "zapcore/json_encoder_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkZapJSONFloat32AndComplex64", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkzapjsonfloat32andcomplex64_9756807534644178564", - "qualified_name": "benchmarkzapjsonfloat32andcomplex64_9756807534644178564.BenchmarkZapJSONFloat32AndComplex64", - "file_path": "zapcore/json_encoder_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkSampler_Check", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarksampler_check_9756807534644178564", - "qualified_name": "benchmarksampler_check_9756807534644178564.BenchmarkSampler_Check", - "file_path": "zapcore/sampler_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkSampler_CheckWithHook", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarksampler_checkwithhook_9756807534644178564", - "qualified_name": "benchmarksampler_checkwithhook_9756807534644178564.BenchmarkSampler_CheckWithHook", - "file_path": "zapcore/sampler_bench_test.go", - "is_external": true - }, - { - "name": "BenchmarkTeeCheck", - "module_path": "go.uber.org/zap/zapcore", - "import_alias": "benchmarkteecheck_9756807534644178564", - "qualified_name": "benchmarkteecheck_9756807534644178564.BenchmarkTeeCheck", - "file_path": "zapcore/tee_logger_bench_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkWriter", - "module_path": "go.uber.org/zap/zapio", - "import_alias": "benchmarkwriter_3748218270869233422", - "qualified_name": "benchmarkwriter_3748218270869233422.BenchmarkWriter", - "file_path": "zapio/writer_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zerolog.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zerolog.snap deleted file mode 100644 index 35866cfd..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__discovery__tests__discover_benchmarks@zerolog.snap +++ /dev/null @@ -1,233 +0,0 @@ ---- -source: go-runner/src/builder/discovery.rs -expression: packages ---- -[ - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkContextAppend", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkcontextappend_4383361269039284158", - "qualified_name": "benchmarkcontextappend_4383361269039284158.BenchmarkContextAppend", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkContextFieldType", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkcontextfieldtype_4383361269039284158", - "qualified_name": "benchmarkcontextfieldtype_4383361269039284158.BenchmarkContextFieldType", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkContextFields", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkcontextfields_4383361269039284158", - "qualified_name": "benchmarkcontextfields_4383361269039284158.BenchmarkContextFields", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkDisabled", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkdisabled_4383361269039284158", - "qualified_name": "benchmarkdisabled_4383361269039284158.BenchmarkDisabled", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkInfo", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkinfo_4383361269039284158", - "qualified_name": "benchmarkinfo_4383361269039284158.BenchmarkInfo", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkLogArrayObject", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarklogarrayobject_4383361269039284158", - "qualified_name": "benchmarklogarrayobject_4383361269039284158.BenchmarkLogArrayObject", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkLogEmpty", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarklogempty_4383361269039284158", - "qualified_name": "benchmarklogempty_4383361269039284158.BenchmarkLogEmpty", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkLogFieldType", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarklogfieldtype_4383361269039284158", - "qualified_name": "benchmarklogfieldtype_4383361269039284158.BenchmarkLogFieldType", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkLogFields", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarklogfields_4383361269039284158", - "qualified_name": "benchmarklogfields_4383361269039284158.BenchmarkLogFields", - "file_path": "benchmark_test.go", - "is_external": false - }, - { - "name": "BenchmarkHooks", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkhooks_4383361269039284158", - "qualified_name": "benchmarkhooks_4383361269039284158.BenchmarkHooks", - "file_path": "hook_test.go", - "is_external": false - }, - { - "name": "BenchmarkSamplers", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarksamplers_4383361269039284158", - "qualified_name": "benchmarksamplers_4383361269039284158.BenchmarkSamplers", - "file_path": "sampler_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkConsoleWriter", - "module_path": "github.com/rs/zerolog", - "import_alias": "benchmarkconsolewriter_4383361269039284158", - "qualified_name": "benchmarkconsolewriter_4383361269039284158.BenchmarkConsoleWriter", - "file_path": "console_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "Benchmark", - "module_path": "github.com/rs/zerolog/diode", - "import_alias": "benchmark_14914425082437298025", - "qualified_name": "benchmark_14914425082437298025.Benchmark", - "file_path": "diode/diode_test.go", - "is_external": true - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkDataRace", - "module_path": "github.com/rs/zerolog/hlog", - "import_alias": "benchmarkdatarace_14719264016234589343", - "qualified_name": "benchmarkdatarace_14719264016234589343.BenchmarkDataRace", - "file_path": "hlog/hlog_test.go", - "is_external": false - }, - { - "name": "BenchmarkHandlers", - "module_path": "github.com/rs/zerolog/hlog", - "import_alias": "benchmarkhandlers_14719264016234589343", - "qualified_name": "benchmarkhandlers_14719264016234589343.BenchmarkHandlers", - "file_path": "hlog/hlog_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAppendString", - "module_path": "github.com/rs/zerolog/internal/cbor", - "import_alias": "benchmarkappendstring_15041621223362855765", - "qualified_name": "benchmarkappendstring_15041621223362855765.BenchmarkAppendString", - "file_path": "internal/cbor/string_test.go", - "is_external": false - }, - { - "name": "BenchmarkAppendTime", - "module_path": "github.com/rs/zerolog/internal/cbor", - "import_alias": "benchmarkappendtime_15041621223362855765", - "qualified_name": "benchmarkappendtime_15041621223362855765.BenchmarkAppendTime", - "file_path": "internal/cbor/time_test.go", - "is_external": false - }, - { - "name": "BenchmarkAppendFloat", - "module_path": "github.com/rs/zerolog/internal/cbor", - "import_alias": "benchmarkappendfloat_15041621223362855765", - "qualified_name": "benchmarkappendfloat_15041621223362855765.BenchmarkAppendFloat", - "file_path": "internal/cbor/types_test.go", - "is_external": false - }, - { - "name": "BenchmarkAppendInt", - "module_path": "github.com/rs/zerolog/internal/cbor", - "import_alias": "benchmarkappendint_15041621223362855765", - "qualified_name": "benchmarkappendint_15041621223362855765.BenchmarkAppendInt", - "file_path": "internal/cbor/types_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkAppendBytes", - "module_path": "github.com/rs/zerolog/internal/json", - "import_alias": "benchmarkappendbytes_16338080240747305392", - "qualified_name": "benchmarkappendbytes_16338080240747305392.BenchmarkAppendBytes", - "file_path": "internal/json/bytes_test.go", - "is_external": false - }, - { - "name": "BenchmarkAppendString", - "module_path": "github.com/rs/zerolog/internal/json", - "import_alias": "benchmarkappendstring_16338080240747305392", - "qualified_name": "benchmarkappendstring_16338080240747305392.BenchmarkAppendString", - "file_path": "internal/json/string_test.go", - "is_external": false - }, - { - "name": "BenchmarkEncoder_AppendFloat32", - "module_path": "github.com/rs/zerolog/internal/json", - "import_alias": "benchmarkencoder_appendfloat32_16338080240747305392", - "qualified_name": "benchmarkencoder_appendfloat32_16338080240747305392.BenchmarkEncoder_AppendFloat32", - "file_path": "internal/json/types_test.go", - "is_external": false - }, - { - "name": "BenchmarkEncoder_AppendFloat64", - "module_path": "github.com/rs/zerolog/internal/json", - "import_alias": "benchmarkencoder_appendfloat64_16338080240747305392", - "qualified_name": "benchmarkencoder_appendfloat64_16338080240747305392.BenchmarkEncoder_AppendFloat64", - "file_path": "internal/json/types_test.go", - "is_external": false - } - ] - }, - { - "raw_package": "[raw_package]", - "benchmarks": [ - { - "name": "BenchmarkLogStack", - "module_path": "github.com/rs/zerolog/pkgerrors", - "import_alias": "benchmarklogstack_4043122862950150244", - "qualified_name": "benchmarklogstack_4043122862950150244.BenchmarkLogStack", - "file_path": "pkgerrors/stacktrace_test.go", - "is_external": false - } - ] - } -] diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__already_patched_import.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__already_patched_import.snap deleted file mode 100644 index 6774659b..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__already_patched_import.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import testing "github.com/CodSpeedHQ/codspeed-go/compat/testing" - -func BenchmarkExample(b *testing.B) { - // benchmark code -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_at_end_of_block.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_at_end_of_block.snap deleted file mode 100644 index f51a9ac7..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_at_end_of_block.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import ( - "fmt" - "strings" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_testing_and_slogassert.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_testing_and_slogassert.snap deleted file mode 100644 index ba2ac9f2..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_testing_and_slogassert.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat -import ( - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "fmt" - "github.com/CodSpeedHQ/codspeed-go/pkg/slogassert" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_comments.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_comments.snap deleted file mode 100644 index eaee04ff..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_comments.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" // for unit tests - "strings" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_extra_whitespace.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_extra_whitespace.snap deleted file mode 100644 index 6303d18c..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_extra_whitespace.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import ( - "fmt" - - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - "strings" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_testing_string.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_testing_string.snap deleted file mode 100644 index db799c5b..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__import_with_testing_string.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -import "fmt" - -func TestExample(t *testing.T) { - fmt.Println("testing") -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__many_testing_imports.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__many_testing_imports.snap deleted file mode 100644 index efb7a1ba..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__many_testing_imports.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package subpackages -import ( - "bytes" - "io" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - fstest "github.com/CodSpeedHQ/codspeed-go/testing/testing/fstest" - iotest "github.com/CodSpeedHQ/codspeed-go/testing/testing/iotest" - synctest "github.com/CodSpeedHQ/codspeed-go/testing/testing/synctest" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__mixed_import_styles.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__mixed_import_styles.snap deleted file mode 100644 index c8b59b4c..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__mixed_import_styles.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - -import ( - "fmt" - "something" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_replacement.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_replacement.snap deleted file mode 100644 index 5bc551fa..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_replacement.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "strings" -) - -func TestExample(t *testing.T) { - // test code -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_tabs.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_tabs.snap deleted file mode 100644 index b8dd1837..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_tabs.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - "strings" -) diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_testing_string.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_testing_string.snap deleted file mode 100644 index 27453e34..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__multiline_import_with_testing_string.snap +++ /dev/null @@ -1,13 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat -import ( - "fmt" - testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" -) - -func TestExample(t *testing.T) { - fmt.Println("testing") -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__package_main.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__package_main.snap deleted file mode 100644 index 75189858..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__package_main.snap +++ /dev/null @@ -1,15 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - -func BenchmarkExample(b *testing.B) { - // benchmark code -} - -func TestExample(t *testing.T) { - s := "package main" -} diff --git a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__single_import_replacement.snap b/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__single_import_replacement.snap deleted file mode 100644 index acc58f7f..00000000 --- a/go-runner/src/builder/snapshots/codspeed_go_runner__builder__patcher__tests__single_import_replacement.snap +++ /dev/null @@ -1,11 +0,0 @@ ---- -source: go-runner/src/builder/patcher.rs -expression: result ---- -package main_compat - -import testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - -func TestExample(t *testing.T) { - // test code -} diff --git a/go-runner/src/builder/template.go b/go-runner/src/builder/template.go deleted file mode 100644 index 9248b2ac..00000000 --- a/go-runner/src/builder/template.go +++ /dev/null @@ -1,85 +0,0 @@ -package main - -import ( - "io" - "reflect" - "regexp" - "time" - - codspeed_testing "github.com/CodSpeedHQ/codspeed-go/testing/testing" - - // Import parent package containing the benchmarks (only for internal tests) - {{#each benchmarks}} - {{#unless is_external}}{{import_alias}} "{{module_path}}"{{/unless}} - {{/each}} -) - -// TestDeps is an implementation of the testing.testDeps interface, -// suitable for passing to [testing.MainStart]. -// -// It is partially copied from `testing/internal/testdeps/deps.go`, and -// only implements the minimum required functionality. -type TestDeps struct {} - -func (d TestDeps) ImportPath() string { return "" } - -var matchPat string -var matchRe *regexp.Regexp - -func (TestDeps) MatchString(pat, str string) (result bool, err error) { - if matchRe == nil || matchPat != pat { - matchPat = pat - matchRe, err = regexp.Compile(matchPat) - if err != nil { - return - } - } - return matchRe.MatchString(str), nil -} - -func (d TestDeps) SetPanicOnExit0(bool) {} -func (d TestDeps) StartCPUProfile(io.Writer) error { return nil } -func (d TestDeps) StopCPUProfile() {} -func (d TestDeps) StartTestLog(io.Writer) {} -func (d TestDeps) StopTestLog() error { return nil } -func (d TestDeps) WriteProfileTo(string, io.Writer, int) error { return nil } - -type corpusEntry = struct { - Parent string - Path string - Data []byte - Values []any - Generation int - IsSeed bool -} - -func (d TestDeps) CoordinateFuzzing(fuzzTime time.Duration, fuzzN int64, minimizeTime time.Duration, minimizeN int64, parallel int, corpus []corpusEntry, types []reflect.Type, corpusDir, cacheDir string) error { - return nil -} -func (d TestDeps) RunFuzzWorker(fn func(corpusEntry) error) error { return nil } -func (d TestDeps) ReadCorpus(dir string, types []reflect.Type) ([]corpusEntry, error) { - return nil, nil -} -func (d TestDeps) CheckCorpus(vals []any, types []reflect.Type) error { - return nil -} -func (d TestDeps) ResetCoverage() {} -func (d TestDeps) SnapshotCoverage() {} -func (d TestDeps) InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64) { - return "", nil, nil -} - -func main() { - var tests = []codspeed_testing.InternalTest{} - var fuzzTargets = []codspeed_testing.InternalFuzzTarget{} - var examples = []codspeed_testing.InternalExample{} - var benchmarks = []codspeed_testing.InternalBenchmark{ - {{#each benchmarks}} - {"{{name}}", - {{#if is_external}}{{name}}{{else}}{{qualified_name}}{{/if}}}, - {{/each}} - } - - m := codspeed_testing.MainStart(TestDeps{}, tests, benchmarks, fuzzTargets, examples) - m.Run() -} diff --git a/go-runner/src/builder/templater.rs b/go-runner/src/builder/templater.rs deleted file mode 100644 index b7e81e25..00000000 --- a/go-runner/src/builder/templater.rs +++ /dev/null @@ -1,291 +0,0 @@ -use std::fs; -use std::path::{Path, PathBuf}; - -use handlebars::Handlebars; -use once_cell::sync::OnceCell; -use serde::{Deserialize, Serialize}; -use tempfile::TempDir; - -use crate::builder::patcher::Patcher; -use crate::builder::{BenchmarkPackage, GoBenchmark}; -use crate::utils; -use crate::{builder::patcher, prelude::*}; - -#[derive(Debug, Serialize)] -struct GoRunnerMetadata { - profile_folder: String, - relative_package_path: String, -} - -#[derive(Debug, Serialize, Deserialize)] -struct TemplateData { - benchmarks: Vec, - module_name: String, -} - -pub struct CodspeedContext { - package: BenchmarkPackage, - profile_dir: PathBuf, - git_root: PathBuf, - target_dir: PathBuf, - - // Artifacts that have to be cleaned up later - patcher: Patcher, - metadata_path: Option, - runner_path: Option, -} - -impl CodspeedContext { - pub fn for_package>( - package: &BenchmarkPackage, - profile_dir: P, - git_root: PathBuf, - target_dir: PathBuf, - ) -> Self { - Self { - patcher: Patcher::new(&target_dir), - package: package.clone(), - profile_dir: profile_dir.as_ref().to_path_buf(), - git_root, - target_dir, - metadata_path: None, - runner_path: None, - } - } - - fn setup_runner_metadata(&mut self) -> anyhow::Result<()> { - // Create a new go-runner.metadata file in the root of the project - // - // The package path will be prepended to the URI. The benchmark will - // find the path relative to the root of the `target_dir`. - // - // This is needed because we could execute a Go project that is a sub-folder - // within a Git repository, then we won't copy the .git folder. Therefore, we - // have to resolve the .git relative path in go-runner and then combine it. - let relative_package_path = utils::get_git_relative_path(&self.package.dir) - .to_string_lossy() - .into(); - debug!("Relative package path: {relative_package_path}"); - - let metadata = GoRunnerMetadata { - profile_folder: self.profile_dir.to_string_lossy().into(), - relative_package_path, - }; - let metadata_path = self.target_dir.join("go-runner.metadata"); - fs::write(&metadata_path, serde_json::to_string_pretty(&metadata)?) - .context("Failed to write go-runner.metadata file")?; - self.metadata_path = Some(metadata_path); - - Ok(()) - } - - fn patch_files(&mut self) -> anyhow::Result<()> { - let package = &self.package; - let target_dir = &self.target_dir; - - // Get files that need to be renamed first - let files = package.test_files().with_context(|| { - anyhow::anyhow!("No test files found for package: {}", package.name) - })?; - - // Patch the imports and package of the test files - // - Renames package declarations (to support main package tests and external tests) - // - Fixes imports to use our compat packages (e.g., testing/quicktest/testify) - let package_path = target_dir.join(self.relative_package_path()?); - let test_file_paths: Vec = files.iter().map(|f| package_path.join(f)).collect(); - - // If we have external tests (e.g. "package {pkg}_test") they have to be - // changed to "package main" so they can be built within the codspeed/ sub-package. - if package.is_external_test_package() { - self.patcher.patch_packages_for_files(&test_file_paths)?; - } else if package.name == "main" { - // If this is a "package main" (not external test), we need to patch ALL .go files in the package directory - // so they all become "package main_compat" and can be imported by the runner. - - info!("Package is 'main' - patching all .go files in package directory"); - self.patcher.patch_all_packages_in_dir(&package_path)?; - } - self.patcher.patch_imports(target_dir)?; - - // Handle test files differently based on whether they're external or internal tests - let codspeed_dir = self.codspeed_dir()?; - fs::create_dir_all(&codspeed_dir).context("Failed to create codspeed directory")?; - - if package.is_external_test_package() { - // For external test packages: copy test files to codspeed/ subdirectory AND rename them - // (remove _test suffix so Go will compile them with `go build`) - // They're now package main and will be built from the subdirectory - self.patcher - .rename_and_move_test_files(&test_file_paths, &codspeed_dir)?; - } else { - // For internal test packages: rename _test.go to _codspeed.go in place - self.patcher.rename_test_files(&test_file_paths)?; - } - - Ok(()) - } - - fn install_codspeed_dependency(&mut self) -> anyhow::Result<()> { - let package = &self.package; - let git_root = &self.git_root; - let target_dir = &self.target_dir; - - // Install codspeed-go dependency at the package module level - // Find the module directory by getting the relative path from git root - let module_dir = Path::new(&package.module.dir) - .strip_prefix(git_root) - .map(|relative_module_path| target_dir.join(relative_module_path)) - .unwrap_or_else(|_| { - // Fall back to target_dir if we can't calculate relative path - target_dir.to_path_buf() - }); - patcher::install_codspeed_dependency(&module_dir)?; - - Ok(()) - } - - fn setup_runner(&mut self) -> anyhow::Result<()> { - let package = &self.package; - - // Generate the codspeed/runner.go file using the template - let mut handlebars = Handlebars::new(); - let template_content = include_str!("template.go"); - handlebars.register_template_string("main", template_content)?; - - // import - // { "", }, - let data = TemplateData { - benchmarks: package.benchmarks.clone(), - module_name: "codspeed_runner".into(), - }; - let rendered = handlebars.render("main", &data)?; - - let runner_path = self.codspeed_dir()?.join("runner.go"); - fs::write(&runner_path, rendered).context("Failed to write runner.go file")?; - self.runner_path = Some(runner_path); - - Ok(()) - } - - pub fn runner_path(&self) -> &PathBuf { - self.runner_path - .as_ref() - .expect("Runner path not set up yet") - } - - fn relative_package_path(&self) -> anyhow::Result { - let package = &self.package; - let git_root = &self.git_root; - - // Calculate the relative path from git root to package directory - let package_dir = Path::new(&package.dir); - let relative_package_path = package_dir.strip_prefix(git_root).context(format!( - "Package dir {:?} is not within git root {:?}", - package.dir, git_root - ))?; - Ok(relative_package_path.to_path_buf()) - } - - fn codspeed_dir(&self) -> anyhow::Result { - let package = &self.package; - let target_dir = &self.target_dir; - let git_root = &self.git_root; - - let package_dir = Path::new(&package.dir); - let relative_package_path = package_dir.strip_prefix(git_root).unwrap_or_else(|_| { - panic!( - "Package dir {:?} is not within git root {:?}", - package.dir, git_root - ) - }); - Ok(target_dir.join(relative_package_path).join("codspeed")) - } -} - -pub struct Templater { - target_dir: OnceCell, -} - -impl Default for Templater { - fn default() -> Self { - Self::new() - } -} - -impl Templater { - pub fn new() -> Self { - Self { - target_dir: OnceCell::new(), - } - } - - /// Runs the templater which sets up a temporary Go project with patched test files and a custom runner. - /// - /// # Returns - /// - /// The path to the generated runner.go file. This should be passed to the `build_binary` function to build - /// the binary that will execute the benchmarks. - pub fn run>( - &self, - package: &BenchmarkPackage, - profile_dir: P, - ) -> anyhow::Result { - // Copy the whole git repository to a build directory - let git_root = if let Ok(git_dir) = utils::get_parent_git_repo_path(&package.module.dir) { - git_dir - } else { - warn!("Could not find git repository root. Falling back to module directory as root"); - PathBuf::from(&package.module.dir) - }; - - // Because we added the projects as git submodules, they'll have a symlink to - // the actual git repository. There is a .git file which only contains the path to - // the actual .git folder. - // $ cat .git - // gitdir: ../../../../.git/modules/go-runner/testdata/projects/hugo - // - // In those cases, we'll have to copy the parent directory rather than the submodule. - // NOTE: This is not the case for all tests, so we have to only do it for submodules. - let is_submodule = fs::read_to_string(git_root.join(".git")) - .map(|content| content.starts_with("gitdir:")) - .unwrap_or(false); - let git_root: PathBuf = if cfg!(test) && is_submodule { - utils::get_parent_git_repo_path(git_root.parent().unwrap()).unwrap() - } else { - git_root - }; - info!("Found git root at {git_root:?}"); - - let target_dir = self - .target_dir - .get_or_try_init(|| -> anyhow::Result { - // Create a temporary target directory for building the modified Go project. - let mut target_dir = TempDir::new()?; - - // We don't want to spend time cleanup any temporary files since the code is only - // run on CI servers which clean up themselves. - // However, when running tests we don't want to fill the disk with temporary files, which - // can cause the tests to fail due to lack of disk space. - if cfg!(not(test)) { - target_dir.disable_cleanup(true); - } - - utils::copy_dir_recursively(&git_root, target_dir.path())?; - - Ok(target_dir) - })?; - - let mut ctx = CodspeedContext::for_package( - package, - &profile_dir, - git_root, - target_dir.path().to_path_buf(), - ); - ctx.install_codspeed_dependency()?; - ctx.setup_runner_metadata()?; - ctx.patch_files()?; - ctx.setup_runner()?; - - Ok(ctx) - } -} diff --git a/go-runner/src/integration_tests.rs b/go-runner/src/integration_tests.rs index d6e22e4d..f0de6ed5 100644 --- a/go-runner/src/integration_tests.rs +++ b/go-runner/src/integration_tests.rs @@ -3,7 +3,7 @@ use rstest::rstest; use std::path::{Path, PathBuf}; use tempfile::TempDir; -use crate::{results::walltime_results::WalltimeResults, utils::can_build_project}; +use crate::results::walltime_results::WalltimeResults; fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { let glob_pattern = profile_dir.join("results"); @@ -88,18 +88,13 @@ fn test_build_and_run(#[case] project_name: &str) { .join("testdata/projects") .join(project_name); - if !can_build_project(&project_dir) { - eprintln!("Skipping test for project {project_name} due to Go version constraints."); - return; - } - let temp_dir = TempDir::new().unwrap(); let profile_dir = temp_dir.path().join("profile"); let cli = crate::cli::Cli { benchtime: "1x".into(), ..Default::default() }; - if let Err(error) = crate::run_benchmarks(&profile_dir, project_dir.as_path(), &cli) { + if let Err(error) = crate::run_benchmarks(&*profile_dir, project_dir.as_path(), &cli) { panic!("Benchmarks couldn't run: {error}"); } diff --git a/go-runner/src/lib.rs b/go-runner/src/lib.rs index db278bc9..1b3f2e6f 100644 --- a/go-runner/src/lib.rs +++ b/go-runner/src/lib.rs @@ -1,16 +1,13 @@ use crate::{ - builder::{BenchmarkPackage, templater::Templater}, prelude::*, results::{raw_result::RawResult, walltime_results::WalltimeBenchmark}, }; use std::{collections::HashMap, path::Path}; -pub mod builder; pub mod cli; pub mod prelude; pub mod results; pub mod runner; -pub(crate) mod utils; #[global_allocator] static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; @@ -21,68 +18,15 @@ mod integration_tests; /// Builds and runs the specified Go project benchmarks, writing results to the .codspeed folder. pub fn run_benchmarks>( profile_dir: P, - project_dir: &Path, + project_dir: P, cli: &crate::cli::Cli, ) -> anyhow::Result<()> { - // 1. Build phase - Benchmark and package discovery - let packages = BenchmarkPackage::from_project(project_dir, &cli.packages)?; - info!("Discovered {} packages", packages.len()); - - let total_benchmarks: usize = packages.iter().map(|p| p.benchmarks.len()).sum(); - info!("Total benchmarks discovered: {total_benchmarks}"); - - for package in &packages { - for benchmark in &package.benchmarks { - info!("Found {:30} in {:?}", benchmark.name, benchmark.file_path); - } - } - - // 2. Generate codspeed runners, build binaries, and execute them - let templater = Templater::new(); - let mut threads = Vec::with_capacity(packages.len()); - for package in &packages { - info!("Generating custom runner for package: {}", package.name); - let ctx = templater.run(package, &profile_dir)?; - - info!("Building binary for package: {}", package.name); - - let binary_path = match builder::build_binary(ctx.runner_path()) { - Ok(binary_path) => binary_path, - Err(e) => { - if cfg!(test) { - panic!("Failed to build {}: {e}", package.name); - } else { - error!("Failed to build {}: {e}", package.name); - continue; - } - } - }; - - if !cli.dry_run { - if let Err(error) = runner::run( - &binary_path, - &["-test.bench", &cli.bench, "-test.benchtime", &cli.benchtime], - ) { - error!("Failed to run benchmarks for {}: {error}", package.name); - continue; - } - - // Collect the results in a new thread, to avoid blocking the main thread at the end. The - // conversions and computations can take a while when we have a lot of iterations. - let profile_dir = profile_dir.as_ref().to_path_buf(); - threads.push(std::thread::spawn(move || { - collect_walltime_results(profile_dir.as_ref()).unwrap(); - })); - } else { - info!("Skipping benchmark execution (dry-run mode)"); - } + if let Err(error) = runner::run(&profile_dir, &project_dir, cli) { + bail!("Failed to run benchmarks: {error}"); } - // Wait for all result collection threads to finish - threads.into_iter().for_each(|t| { - t.join() - .expect("Failed to join collect_walltime_results thread") - }); + let profile_dir = profile_dir.as_ref().to_path_buf(); + collect_walltime_results(&profile_dir).unwrap(); Ok(()) } diff --git a/go-runner/src/main.rs b/go-runner/src/main.rs index 88afd2c4..b67d1eba 100644 --- a/go-runner/src/main.rs +++ b/go-runner/src/main.rs @@ -11,7 +11,7 @@ fn main() -> anyhow::Result<()> { let cli = Cli::parse(); let profile_dir = std::env::var("CODSPEED_PROFILE_FOLDER").unwrap_or("/tmp".into()); - codspeed_go_runner::run_benchmarks(profile_dir, Path::new("."), &cli)?; + codspeed_go_runner::run_benchmarks(Path::new(&profile_dir), Path::new("."), &cli)?; Ok(()) } diff --git a/go-runner/src/runner.rs b/go-runner/src/runner.rs deleted file mode 100644 index 37c142b3..00000000 --- a/go-runner/src/runner.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::prelude::*; -use std::{path::Path, process::Command}; - -fn run_cmd>(binary_path: P, run_args: &[&str]) -> anyhow::Result { - let binary_path = binary_path.as_ref(); - debug!("Running codspeed benchmark binary: {binary_path:?}"); - - // Execute it from the folder with the benchmarks: - // ``` - // benches/ <-- module_root - // codspeed/ - // runner.go - // runner.bin <-- binary_path - // foo_test.go - // fib_test.go - // ``` - let module_root = binary_path.parent().unwrap().parent().unwrap(); - let mut cmd = Command::new(binary_path); - cmd.args(run_args).current_dir(module_root); - Ok(cmd) -} - -fn check_success(output: &std::process::Output) -> anyhow::Result { - if !output.status.success() { - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - warn!("Command output: {stdout}"); - warn!("Command error output: {stderr}"); - - bail!("Failed to run benchmark. Exit status: {}", output.status); - } - Ok(String::from_utf8_lossy(&output.stdout).to_string()) -} - -/// Runs the cmd and returns the output. -pub fn run_with_stdout>( - binary_path: P, - run_args: &[&str], -) -> anyhow::Result { - let mut cmd = run_cmd(binary_path, run_args)?; - let output = cmd.output().context("Failed to execute go build command")?; - check_success(&output) -} - -/// Runs the cmd and forwards the output to stdout/stderr. -pub fn run>(binary_path: P, run_args: &[&str]) -> anyhow::Result<()> { - let mut cmd = run_cmd(binary_path, run_args)?; - let output = cmd - .stdout(std::process::Stdio::inherit()) - .stderr(std::process::Stdio::inherit()) - .output() - .context("Failed to execute go build command")?; - - check_success(&output).map(|_| ()) -} diff --git a/go-runner/src/runner/mod.rs b/go-runner/src/runner/mod.rs new file mode 100644 index 00000000..45a735ec --- /dev/null +++ b/go-runner/src/runner/mod.rs @@ -0,0 +1,71 @@ +use crate::cli::Cli; +use crate::prelude::*; +use std::{path::Path, process::Command}; +use tempfile::TempDir; + +mod overlay; + +pub fn run_cmd>( + profile_dir: P, + dir: P, + cli: &Cli, +) -> anyhow::Result<(TempDir, Command)> { + let (_dir, overlay_file) = overlay::get_overlay_file(profile_dir.as_ref())?; + + // Convert the CLI struct into a command: + let mut cmd = Command::new("go"); + cmd.args([ + "test", + "-overlay", + &overlay_file.to_string_lossy(), + "-bench", + &cli.bench, + "-benchtime", + &cli.benchtime, + ]); + cmd.args(&cli.packages); + cmd.current_dir(dir); + + Ok((_dir, cmd)) +} + +fn check_success(output: &std::process::Output) -> anyhow::Result { + if !output.status.success() { + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + warn!("Command output: {stdout}"); + warn!("Command error output: {stderr}"); + + bail!( + "Failed to run benchmark. Exit status: {}\n\nStdout:\n{}\n\nStderr:\n{}", + output.status, + stdout, + stderr + ); + } + Ok(String::from_utf8_lossy(&output.stdout).to_string()) +} + +/// Runs the cmd and returns the output. +pub fn run_with_stdout>( + profile_dir: P, + dir: P, + cli: &Cli, +) -> anyhow::Result { + let (_dir, mut cmd) = run_cmd(profile_dir, dir, cli)?; + let output = cmd.output().context("Failed to execute go build command")?; + check_success(&output) +} + +/// Runs the cmd and forwards the output to stdout/stderr. +pub fn run>(profile_dir: P, dir: P, cli: &Cli) -> anyhow::Result<()> { + let (_dir, mut cmd) = run_cmd(profile_dir, dir, cli)?; + let output = cmd + .stdout(std::process::Stdio::inherit()) + .stderr(std::process::Stdio::inherit()) + .output() + .context("Failed to execute go build command")?; + + check_success(&output).map(|_| ()) +} diff --git a/go-runner/src/runner/overlay/instrument_hooks.rs b/go-runner/src/runner/overlay/instrument_hooks.rs new file mode 100644 index 00000000..710231bf --- /dev/null +++ b/go-runner/src/runner/overlay/instrument_hooks.rs @@ -0,0 +1,37 @@ +use crate::prelude::*; +use anyhow::{Result, ensure}; +use flate2::read::GzDecoder; +use std::path::PathBuf; +use tar::Archive; +use tempfile::TempDir; + +const INSTRUMENT_HOOKS_REPO: &str = "CodSpeedHQ/instrument-hooks"; +const INSTRUMENT_HOOKS_COMMIT: &str = "1752e9e4eae585e26703932d0055a1473dd77048"; + +/// Get the instrument-hooks directory, downloading if necessary +/// Downloads to /tmp/codspeed-instrument-hooks-{commit}/ +pub fn download_instrument_hooks(temp_dir: &TempDir) -> Result { + let hooks_dir = temp_dir + .path() + .join(format!("instrument-hooks-{}", INSTRUMENT_HOOKS_COMMIT)); + + if !hooks_dir.exists() { + debug!("Downloading instrument-hooks to {:?}", hooks_dir); + let url = format!( + "https://github.com/{}/archive/{}.tar.gz", + INSTRUMENT_HOOKS_REPO, INSTRUMENT_HOOKS_COMMIT + ); + let content = reqwest::blocking::get(&url)?.bytes()?; + + // This will unpack to /tmp/codspeed-instrument-hooks-{commit}/ + let tar = GzDecoder::new(&*content); + let mut archive = Archive::new(tar); + archive.unpack(temp_dir.path())?; + + ensure!(hooks_dir.exists(), "Failed to download instrument-hooks"); + } else { + debug!("Using existing instrument-hooks at {:?}", hooks_dir); + } + + Ok(hooks_dir) +} diff --git a/go-runner/src/runner/overlay/mod.rs b/go-runner/src/runner/overlay/mod.rs new file mode 100644 index 00000000..79d61407 --- /dev/null +++ b/go-runner/src/runner/overlay/mod.rs @@ -0,0 +1,88 @@ +use anyhow::{bail, ensure}; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, + process::Command, +}; +use tempfile::TempDir; + +mod instrument_hooks; + +const OVERLAY_TEMPLATES: &[(&str, &str)] = &[ + ( + "benchmark.go", + include_str!("../../../overlay/benchmark.go"), + ), + ("codspeed.go", include_str!("../../../overlay/codspeed.go")), + ( + "instrument-hooks.go", + include_str!("../../../overlay/instrument-hooks.go"), + ), +]; + +fn get_overlay_files( + profile_dir: &Path, + temp_dir: &TempDir, +) -> anyhow::Result> { + let instrument_hooks_dir = instrument_hooks::download_instrument_hooks(temp_dir)?; + + let mut files = HashMap::new(); + for (file_name, content) in OVERLAY_TEMPLATES { + let content = content + .replace( + "@@INSTRUMENT_HOOKS_DIR@@", + &instrument_hooks_dir.to_string_lossy(), + ) + .replace("@@CODSPEED_PROFILE_DIR@@", &profile_dir.to_string_lossy()) + .replace("@@GO_RUNNER_VERSION@@", env!("CARGO_PKG_VERSION")); + files.insert(file_name.to_string(), content); + } + Ok(files) +} + +pub fn get_overlay_file(profile_dir: &Path) -> anyhow::Result<(TempDir, PathBuf)> { + let overlay_dir = TempDir::new()?; + let goroot_dir = find_goroot()?.join("src").join("testing"); + ensure!(goroot_dir.exists(), "GOROOT/src/testing does not exist"); + + // Put all the overlay files into $GOROOT/src/testing + let mut replaces = HashMap::new(); + for (file_name, content) in get_overlay_files(profile_dir, &overlay_dir)? { + let real_path = goroot_dir.join(&file_name); + let patch_path = overlay_dir.path().join(&file_name); + + std::fs::write(&patch_path, content)?; + replaces.insert(real_path, patch_path); + } + + // Construct the JSON string with the replaces + let replaces = replaces + .iter() + .map(|(k, v)| (k.to_string_lossy(), v.to_string_lossy())) + .collect::>(); + let json = serde_json::json!( + { + "Replace": replaces + } + ) + .to_string(); + + let overlay_file = overlay_dir.path().join("overlay.json"); + std::fs::write(&overlay_file, json)?; + Ok((overlay_dir, overlay_file)) +} + +fn find_goroot() -> anyhow::Result { + let output = Command::new("go").args(["env", "GOROOT"]).output()?; + if !output.status.success() { + bail!("Failed to find $GOROOT"); + } + + let goroot = String::from_utf8_lossy(&output.stdout).trim().to_string(); + let path = PathBuf::from(goroot); + if !path.exists() { + bail!("GOROOT doesn't exist: {:?}", path); + } + + Ok(path) +} diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap index 2a7ef40a..537f7c50 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap @@ -57,6 +57,17 @@ expression: results "max_rounds": null }, "stats": "[stats]" + }, + { + "name": "BenchmarkFibonacci20", + "uri": "go-runner/testdata/projects/example-with-test-package/fib_external/fib_integration_test.go::BenchmarkFibonacci20", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" } ] }, @@ -93,28 +104,5 @@ expression: results "stats": "[stats]" } ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkFibonacci20", - "uri": "go-runner/testdata/projects/example-with-test-package/fib_external/fib_integration_test.go::BenchmarkFibonacci20", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] } ] diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap index 343cedbe..c700368b 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap @@ -466,8 +466,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMultiWriteSyncer::2_discarder", - "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::2_discarder", + "name": "BenchmarkJSONLogMarshalerFunc", + "uri": "zapcore/json_encoder_bench_test.go::BenchmarkJSONLogMarshalerFunc", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -477,8 +477,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMultiWriteSyncer::4_discarder", - "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::4_discarder", + "name": "BenchmarkMultiWriteSyncer::2_discarder", + "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::2_discarder", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -488,8 +488,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMultiWriteSyncer::4_discarder_with_buffer", - "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::4_discarder_with_buffer", + "name": "BenchmarkMultiWriteSyncer::4_discarder", + "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::4_discarder", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -499,8 +499,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkWriteSyncer::write_file_with_no_buffer", - "uri": "zapcore/write_syncer_bench_test.go::BenchmarkWriteSyncer::write_file_with_no_buffer", + "name": "BenchmarkMultiWriteSyncer::4_discarder_with_buffer", + "uri": "zapcore/write_syncer_bench_test.go::BenchmarkMultiWriteSyncer::4_discarder_with_buffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -508,22 +508,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkBuffers::ByteSlice", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::ByteSlice", + "name": "BenchmarkSampler_Check::100_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::100_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -533,8 +521,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBuffers::BytesBuffer", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::BytesBuffer", + "name": "BenchmarkSampler_Check::50_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::50_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -544,8 +532,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBuffers::CustomBuffer", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::CustomBuffer", + "name": "BenchmarkSampler_Check::7_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::7_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -553,22 +541,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkJSONLogMarshalerFunc", - "uri": "zapcore/json_encoder_bench_test.go::BenchmarkJSONLogMarshalerFunc", + "name": "BenchmarkSampler_CheckWithHook::100_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::100_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -578,8 +554,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_Check::100_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::100_keys", + "name": "BenchmarkSampler_CheckWithHook::50_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::50_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -589,8 +565,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_Check::50_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::50_keys", + "name": "BenchmarkSampler_CheckWithHook::7_keys", + "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::7_keys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -600,8 +576,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_Check::7_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_Check::7_keys", + "name": "BenchmarkStandardJSON", + "uri": "zapcore/json_encoder_bench_test.go::BenchmarkStandardJSON", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -611,8 +587,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_CheckWithHook::100_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::100_keys", + "name": "BenchmarkTeeCheck", + "uri": "zapcore/tee_logger_bench_test.go::BenchmarkTeeCheck", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -622,8 +598,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_CheckWithHook::50_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::50_keys", + "name": "BenchmarkWriteSyncer::write_file_with_no_buffer", + "uri": "zapcore/write_syncer_bench_test.go::BenchmarkWriteSyncer::write_file_with_no_buffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -633,8 +609,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSampler_CheckWithHook::7_keys", - "uri": "zapcore/sampler_bench_test.go::BenchmarkSampler_CheckWithHook::7_keys", + "name": "BenchmarkZapConsole", + "uri": "zapcore/console_encoder_bench_test.go::BenchmarkZapConsole", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -644,8 +620,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkStandardJSON", - "uri": "zapcore/json_encoder_bench_test.go::BenchmarkStandardJSON", + "name": "BenchmarkZapJSON", + "uri": "zapcore/json_encoder_bench_test.go::BenchmarkZapJSON", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -655,8 +631,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTeeCheck", - "uri": "zapcore/tee_logger_bench_test.go::BenchmarkTeeCheck", + "name": "BenchmarkZapJSONFloat32AndComplex64", + "uri": "zapcore/json_encoder_bench_test.go::BenchmarkZapJSONFloat32AndComplex64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -664,10 +640,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkZapConsole", - "uri": "zapcore/console_encoder_bench_test.go::BenchmarkZapConsole", + "name": "BenchmarkBuffers::ByteSlice", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::ByteSlice", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -677,8 +665,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkZapJSON", - "uri": "zapcore/json_encoder_bench_test.go::BenchmarkZapJSON", + "name": "BenchmarkBuffers::BytesBuffer", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::BytesBuffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -688,8 +676,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkZapJSONFloat32AndComplex64", - "uri": "zapcore/json_encoder_bench_test.go::BenchmarkZapJSONFloat32AndComplex64", + "name": "BenchmarkBuffers::CustomBuffer", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::CustomBuffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap index 114866c5..d3c5fc64 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap @@ -488,19 +488,7 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { "name": "BenchmarkContextAppend", "uri": "benchmark_test.go::BenchmarkContextAppend", diff --git a/go-runner/src/utils.rs b/go-runner/src/utils.rs deleted file mode 100644 index 43e80b1c..00000000 --- a/go-runner/src/utils.rs +++ /dev/null @@ -1,96 +0,0 @@ -#[cfg(test)] -use crate::prelude::*; -use std::io; -use std::path::{Path, PathBuf}; - -pub fn copy_dir_recursively(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { - let excludes = vec!["node_modules".into(), "target".into()]; - let includes = vec![]; - dircpy::copy_dir_advanced(src, dst, true, true, true, excludes, includes)?; - Ok(()) -} - -pub fn get_parent_git_repo_path(abs_path: &Path) -> io::Result { - if abs_path.join(".git").exists() { - Ok(abs_path.to_path_buf()) - } else { - get_parent_git_repo_path( - abs_path - .parent() - .ok_or(io::Error::from(io::ErrorKind::NotFound))?, - ) - } -} - -pub fn get_git_relative_path

(abs_path: P) -> PathBuf -where - P: AsRef, -{ - if let Ok(canonicalized_abs_path) = abs_path.as_ref().canonicalize() { - // `repo_path` is still canonicalized as it is a subpath of `canonicalized_abs_path` - if let Ok(repo_path) = get_parent_git_repo_path(&canonicalized_abs_path) { - canonicalized_abs_path - .strip_prefix(repo_path) - .expect("Repository path is malformed.") - .to_path_buf() - } else { - canonicalized_abs_path - } - } else { - abs_path.as_ref().to_path_buf() - } -} - -#[cfg(test)] -fn go_version() -> anyhow::Result { - use anyhow::Context; - - let output = std::process::Command::new("go").arg("version").output()?; - if !output.status.success() { - panic!("Failed to get Go version"); - } - let output = String::from_utf8_lossy(&output.stdout); - - // Example output: go version go1.24.9 linux/amd64 - let go_version_str = output - .split_whitespace() - .nth(2) - .context("Failed to parse Go version")? - .strip_prefix("go") - .context("Failed to strip 'go' prefix")?; - Ok(semver::Version::parse(go_version_str)?) -} - -// Check whether the go.mod expects a specific Go version, and skip the test if not met -#[cfg(test)] -fn project_go_version(project_dir: &Path) -> Option { - let go_mod_path = project_dir.join("go.mod"); - if !go_mod_path.exists() { - return None; - } - - let go_mod_content = std::fs::read_to_string(go_mod_path).unwrap_or_default(); - for line in go_mod_content.lines() { - let Some(version_str) = line.strip_prefix("go ") else { - continue; - }; - - return semver::VersionReq::parse(version_str).ok(); - } - - None -} - -#[cfg(test)] -pub fn can_build_project(project_dir: &Path) -> bool { - if let Some(required_version) = project_go_version(project_dir) { - let current_version = go_version().unwrap(); - info!( - "Project requires Go {}, current version is {}", - required_version, current_version - ); - required_version.matches(¤t_version) - } else { - true - } -} diff --git a/go-runner/tests/error_file.rs b/go-runner/tests/error_file.rs index 364788e6..6323e6b8 100644 --- a/go-runner/tests/error_file.rs +++ b/go-runner/tests/error_file.rs @@ -1,17 +1,22 @@ pub mod utils; -use utils::run_with_args; +use codspeed_go_runner::cli::Cli; +use utils::run_with_cli; #[test] pub fn test_error_has_test_filename() { - let stdout = run_with_args( - "tests/error_file.in", - &["-test.bench", "BenchmarkErrorFile", "-test.benchtime", "1x"], - ) - .unwrap(); + let cli = Cli { + bench: "BenchmarkErrorFile".to_string(), + benchtime: "1x".to_string(), + packages: vec!["./...".to_string()], + dry_run: false, + }; + let result = run_with_cli("tests/error_file.in", &cli); + assert!(result.is_err(), "Expected an error but got success"); - eprintln!("Error output: {stdout}"); - assert!(stdout.contains("this_should_be_in_stdout")); - assert!(stdout.contains("error_test.go")); - assert!(!stdout.contains("error_codspeed.go")); + let error_msg = result.unwrap_err().to_string(); + eprintln!("Error output: {error_msg}"); + assert!(error_msg.contains("this_should_be_in_stdout")); + assert!(error_msg.contains("error_test.go")); + assert!(!error_msg.contains("error_codspeed.go")); } diff --git a/go-runner/tests/pkg_arg.rs b/go-runner/tests/pkg_arg.rs index ad093f29..5017459e 100644 --- a/go-runner/tests/pkg_arg.rs +++ b/go-runner/tests/pkg_arg.rs @@ -1,5 +1,5 @@ use codspeed_go_runner::cli::Cli; -use utils::{run_with_cli, run_with_cli_multi}; +use utils::run_with_cli; pub mod utils; @@ -30,7 +30,7 @@ pub fn test_pkg_arg_all_packages() { packages: vec!["./...".to_string()], dry_run: false, }; - let stdout = run_with_cli_multi("tests/pkg_arg.in", &cli).unwrap(); + let stdout = run_with_cli("tests/pkg_arg.in", &cli).unwrap(); // Should contain output from all benchmarks when using ./... assert!(stdout.contains("foo_bench_1")); @@ -47,7 +47,7 @@ pub fn test_pkg_arg_multiple_packages() { packages: vec!["./foo".to_string(), "./bar".to_string()], dry_run: false, }; - let stdout = run_with_cli_multi("tests/pkg_arg.in", &cli).unwrap(); + let stdout = run_with_cli("tests/pkg_arg.in", &cli).unwrap(); // Should contain output from both foo and bar packages assert!(stdout.contains("foo_bench_1")); diff --git a/go-runner/tests/utils.rs b/go-runner/tests/utils.rs index e642889b..12e4b7a9 100644 --- a/go-runner/tests/utils.rs +++ b/go-runner/tests/utils.rs @@ -1,56 +1,9 @@ -use codspeed_go_runner::{ - builder::{self, BenchmarkPackage, templater::Templater}, - cli::Cli, - runner, -}; +use codspeed_go_runner::{cli::Cli, runner}; use std::path::Path; -/// Helper function to run a single package with arguments -pub fn run_package_with_args(package: &BenchmarkPackage, args: &[&str]) -> anyhow::Result { - let profile_dir = tempfile::TempDir::new()?; - let templater = Templater::new(); - let ctx = templater.run(package, profile_dir.as_ref())?; - let binary_path = builder::build_binary(ctx.runner_path())?; - runner::run_with_stdout(&binary_path, args) -} - -/// Helper function to run tests in a directory with specific arguments -pub fn run_with_args>(dir: P, args: &[&str]) -> anyhow::Result { - assert!(dir.as_ref().exists()); - - let packages = BenchmarkPackage::from_project(dir.as_ref(), &["./...".to_string()])?; - assert_eq!(packages.len(), 1); - - run_package_with_args(&packages[0], args) -} - /// Helper function to run a single package using CLI configuration pub fn run_with_cli>(dir: P, cli: &Cli) -> anyhow::Result { assert!(dir.as_ref().exists()); - - let packages = BenchmarkPackage::from_project(dir.as_ref(), &cli.packages)?; - assert_eq!( - packages.len(), - 1, - "Currently only single package is supported" - ); - - let args = ["-test.bench", &cli.bench, "-test.benchtime", &cli.benchtime]; - run_package_with_args(&packages[0], &args) -} - -/// Helper function to run multiple packages using CLI configuration -pub fn run_with_cli_multi>(dir: P, cli: &Cli) -> anyhow::Result { - assert!(dir.as_ref().exists()); - - let packages = BenchmarkPackage::from_project(dir.as_ref(), &cli.packages)?; - - let mut all_stdout = String::new(); - for package in &packages { - let args = ["-test.bench", &cli.bench, "-test.benchtime", &cli.benchtime]; - let stdout = run_package_with_args(package, &args)?; - all_stdout.push_str(&stdout); - } - - Ok(all_stdout) + let stdout = runner::run_with_stdout(Path::new("/tmp"), dir.as_ref(), cli)?; + Ok(stdout) } diff --git a/go.mod b/go.mod index 74556f70..124f58c2 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,3 @@ module github.com/CodSpeedHQ/codspeed-go go 1.24.3 - -require ( - github.com/google/go-cmp v0.7.0 - github.com/kr/pretty v0.3.1 -) - -require ( - github.com/kr/text v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect -) diff --git a/go.sum b/go.sum index faf8f26a..e69de29b 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +0,0 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= From 4d1e0d3f4839621bb394606b87fb8618b4377c50 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:02:10 +0100 Subject: [PATCH 05/13] fix(go-runner): only execute benchmarks, exclude tests --- go-runner/src/runner/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/go-runner/src/runner/mod.rs b/go-runner/src/runner/mod.rs index 45a735ec..c51d1dee 100644 --- a/go-runner/src/runner/mod.rs +++ b/go-runner/src/runner/mod.rs @@ -5,7 +5,7 @@ use tempfile::TempDir; mod overlay; -pub fn run_cmd>( +fn run_cmd>( profile_dir: P, dir: P, cli: &Cli, @@ -22,10 +22,16 @@ pub fn run_cmd>( &cli.bench, "-benchtime", &cli.benchtime, + // Dont' run tests, only benchmarks + "-run=^$", ]); cmd.args(&cli.packages); cmd.current_dir(dir); + // Create isolated Go caches to avoid conflicts when tests run concurrently + cmd.env("GOCACHE", _dir.path().join("gocache")); + cmd.env("GOMODCACHE", _dir.path().join("gomodcache")); + Ok((_dir, cmd)) } From 186940895d067b9fc913a88dc4724ac48a329d98 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:05:16 +0100 Subject: [PATCH 06/13] chore(go-runner): remove dry-run --- go-runner/src/cli.rs | 35 ----------------------------------- go-runner/tests/error_file.rs | 1 - go-runner/tests/pkg_arg.rs | 3 --- 3 files changed, 39 deletions(-) diff --git a/go-runner/src/cli.rs b/go-runner/src/cli.rs index 607a5936..c10a5899 100644 --- a/go-runner/src/cli.rs +++ b/go-runner/src/cli.rs @@ -16,9 +16,6 @@ pub struct Cli { /// Package patterns to run benchmarks for pub packages: Vec, - - /// Build benchmarks but don't execute them - pub dry_run: bool, } impl Default for Cli { @@ -27,7 +24,6 @@ impl Default for Cli { bench: ".".into(), benchtime: "3s".into(), packages: vec!["./...".into()], - dry_run: false, } } } @@ -109,9 +105,6 @@ UNSUPPORTED FLAGS (will be warned about): s if s.starts_with("-benchtime=") => { instance.benchtime = s.split_once('=').unwrap().1.to_string(); } - "--dry-run" => { - instance.dry_run = true; - } s if s.starts_with('-') => { eprintln!( "warning: flag '{s}' is not supported by CodSpeed Go runner, ignoring" @@ -222,32 +215,4 @@ mod tests { let result = str_to_iter("go-runner test -unknown"); assert!(result.is_ok()); } - - #[test] - fn test_cli_parse_dry_run_flag() { - let cli = str_to_iter("go-runner test --dry-run").unwrap(); - assert!(cli.dry_run); - - let cli = str_to_iter("go-runner test").unwrap(); - assert!(!cli.dry_run); - } - - #[test] - fn test_cli_parse_dry_run_with_other_flags() { - let cli = - str_to_iter("go-runner test --dry-run -bench=BenchmarkFoo -benchtime 5s").unwrap(); - assert!(cli.dry_run); - assert_eq!(cli.bench, "BenchmarkFoo"); - assert_eq!(cli.benchtime, "5s"); - } - - #[test] - fn test_cli_parse_dry_run_with_packages() { - let cli = str_to_iter("go-runner test --dry-run ./pkg1 ./pkg2").unwrap(); - assert!(cli.dry_run); - assert_eq!( - cli.packages, - vec!["./pkg1".to_string(), "./pkg2".to_string()] - ); - } } diff --git a/go-runner/tests/error_file.rs b/go-runner/tests/error_file.rs index 6323e6b8..d25d14c5 100644 --- a/go-runner/tests/error_file.rs +++ b/go-runner/tests/error_file.rs @@ -9,7 +9,6 @@ pub fn test_error_has_test_filename() { bench: "BenchmarkErrorFile".to_string(), benchtime: "1x".to_string(), packages: vec!["./...".to_string()], - dry_run: false, }; let result = run_with_cli("tests/error_file.in", &cli); assert!(result.is_err(), "Expected an error but got success"); diff --git a/go-runner/tests/pkg_arg.rs b/go-runner/tests/pkg_arg.rs index 5017459e..dc198cd3 100644 --- a/go-runner/tests/pkg_arg.rs +++ b/go-runner/tests/pkg_arg.rs @@ -9,7 +9,6 @@ pub fn test_pkg_arg_filters_correctly() { bench: "BenchmarkBar1".to_string(), benchtime: "1x".to_string(), packages: vec!["./bar".to_string()], - dry_run: false, }; let stdout = run_with_cli("tests/pkg_arg.in", &cli).unwrap(); @@ -28,7 +27,6 @@ pub fn test_pkg_arg_all_packages() { bench: ".".to_string(), benchtime: "1x".to_string(), packages: vec!["./...".to_string()], - dry_run: false, }; let stdout = run_with_cli("tests/pkg_arg.in", &cli).unwrap(); @@ -45,7 +43,6 @@ pub fn test_pkg_arg_multiple_packages() { bench: ".".to_string(), benchtime: "1x".to_string(), packages: vec!["./foo".to_string(), "./bar".to_string()], - dry_run: false, }; let stdout = run_with_cli("tests/pkg_arg.in", &cli).unwrap(); From 571e334c0f3ddd23747539ba3db62f682a0b58a2 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:12:30 +0100 Subject: [PATCH 07/13] chore(go-runner): remove hugo test It's super slow, taking alone around 15-20 minutes which isn't ideal for CI. Since we are using the `go test` CLI now, the other tests will cover all of the edge cases and we can safely remove it. --- .gitmodules | 3 - go-runner/src/integration_tests.rs | 1 - ..._tests__assert_results_snapshots@hugo.snap | 3684 ----------------- go-runner/testdata/projects/hugo | 1 - 4 files changed, 3689 deletions(-) delete mode 100644 go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@hugo.snap delete mode 160000 go-runner/testdata/projects/hugo diff --git a/.gitmodules b/.gitmodules index d266bffd..72f72309 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,9 +10,6 @@ [submodule "go-runner/testdata/projects/fuego"] path = go-runner/testdata/projects/fuego url = https://github.com/go-fuego/fuego -[submodule "go-runner/testdata/projects/hugo"] - path = go-runner/testdata/projects/hugo - url = https://github.com/gohugoio/hugo.git [submodule "go-runner/testdata/projects/zerolog"] path = go-runner/testdata/projects/zerolog url = https://github.com/rs/zerolog diff --git a/go-runner/src/integration_tests.rs b/go-runner/src/integration_tests.rs index f0de6ed5..58f92731 100644 --- a/go-runner/src/integration_tests.rs +++ b/go-runner/src/integration_tests.rs @@ -71,7 +71,6 @@ fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { #[case::golang_benchmarks("golang-benchmarks")] #[case::zerolog("zerolog")] #[case::zap("zap")] -#[case::hugo("hugo")] #[case::fuego("fuego")] #[case::cli_runtime("cli-runtime")] #[case::quic_go("quic-go")] diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@hugo.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@hugo.snap deleted file mode 100644 index 18101e53..00000000 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@hugo.snap +++ /dev/null @@ -1,3684 +0,0 @@ ---- -source: go-runner/src/integration_tests.rs -expression: results ---- -[ - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkAbsURL::absurl", - "uri": "helpers/url_test.go::BenchmarkAbsURL::absurl", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAbsURL::relurl", - "uri": "helpers/url_test.go::BenchmarkAbsURL::relurl", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReaderContains", - "uri": "helpers/general_test.go::BenchmarkReaderContains", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkRelURL", - "uri": "helpers/url_test.go::BenchmarkRelURL", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTotalWords", - "uri": "helpers/content_test.go::BenchmarkTotalWords", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTrimShortHTML", - "uri": "helpers/content_test.go::BenchmarkTrimShortHTML", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkUniqueStrings::Reuse_slice", - "uri": "helpers/general_test.go::BenchmarkUniqueStrings::Reuse_slice", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkUniqueStrings::Reuse_slice_sorted", - "uri": "helpers/general_test.go::BenchmarkUniqueStrings::Reuse_slice_sorted", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkUniqueStrings::Safe", - "uri": "helpers/general_test.go::BenchmarkUniqueStrings::Safe", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkAbsURL", - "uri": "transform/urlreplacers/absurlreplacer_test.go::BenchmarkAbsURL", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAbsURLSrcset", - "uri": "transform/urlreplacers/absurlreplacer_test.go::BenchmarkAbsURLSrcset", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXMLAbsURL", - "uri": "transform/urlreplacers/absurlreplacer_test.go::BenchmarkXMLAbsURL", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXMLAbsURLSrcset", - "uri": "transform/urlreplacers/absurlreplacer_test.go::BenchmarkXMLAbsURLSrcset", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkBaseline", - "uri": "hugolib/hugo_smoke_test.go::BenchmarkBaseline", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascade::langs-1", - "uri": "hugolib/cascade_test.go::BenchmarkCascade::langs-1", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascade::langs-3", - "uri": "hugolib/cascade_test.go::BenchmarkCascade::langs-3", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascade::langs-5", - "uri": "hugolib/cascade_test.go::BenchmarkCascade::langs-5", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascade::langs-7", - "uri": "hugolib/cascade_test.go::BenchmarkCascade::langs-7", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascade::langs-9", - "uri": "hugolib/cascade_test.go::BenchmarkCascade::langs-9", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCascadeTarget::Kind", - "uri": "hugolib/cascade_test.go::BenchmarkCascadeTarget::Kind", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetPage", - "uri": "hugolib/pagecollections_test.go::BenchmarkGetPage", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetPageRegular::From_root", - "uri": "hugolib/pagecollections_test.go::BenchmarkGetPageRegular::From_root", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetPageRegular::Page_relative", - "uri": "hugolib/pagecollections_test.go::BenchmarkGetPageRegular::Page_relative", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkMergeByLanguage", - "uri": "hugolib/pages_language_merge_test.go::BenchmarkMergeByLanguage", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.Pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.Pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.Pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.Pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.RegularPages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.RegularPages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.RegularPages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.RegularPages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.RegularPagesRecursive-300", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.RegularPagesRecursive-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagePageCollections::.RegularPagesRecursive-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagePageCollections::.RegularPagesRecursive-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::.Next-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::.Next-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::.Next-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::.Next-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::.Prev-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::.Prev-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::.Prev-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::.Prev-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.ByTitle.Next-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.ByTitle.Next-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.ByTitle.Next-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.ByTitle.Next-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Next-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Next-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Next-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Next-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Prev-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Prev-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Prev-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Prev-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Shuffled.Next-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Shuffled.Next-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Shuffled.Next-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Shuffled.Next-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Shuffled.Prev-pages-300", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Shuffled.Prev-pages-300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPagesPrevNext::Pages.Shuffled.Prev-pages-5000", - "uri": "hugolib/pages_test.go::BenchmarkPagesPrevNext::Pages.Shuffled.Prev-pages-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkRebuildContentFileChange", - "uri": "hugolib/rebuild_test.go::BenchmarkRebuildContentFileChange", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplaceShortcodeTokens", - "uri": "hugolib/shortcode_test.go::BenchmarkReplaceShortcodeTokens", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkResourceChainPostProcess", - "uri": "hugolib/resource_chain_test.go::BenchmarkResourceChainPostProcess", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkShortcodesInSite", - "uri": "hugolib/shortcode_test.go::BenchmarkShortcodesInSite", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Bundle_with_JSON_file", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Bundle_with_JSON_file", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Bundle_with_image", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Bundle_with_image", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Deep_content_tree", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Deep_content_tree", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_List_terms", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_List_terms", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Many_HTML_templates", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Many_HTML_templates", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Page_collections", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Page_collections", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_TOML_front_matter", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_TOML_front_matter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Edit_Tags_and_categories", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Edit_Tags_and_categories", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Bundle_with_JSON_file", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Bundle_with_JSON_file", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Bundle_with_image", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Bundle_with_image", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Canonify_URLs", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Canonify_URLs", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Deep_content_tree", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Deep_content_tree", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_List_terms", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_List_terms", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Many_HTML_templates", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Many_HTML_templates", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Page_collections", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Page_collections", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_TOML_front_matter", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_TOML_front_matter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSiteNew::Regular_Tags_and_categories", - "uri": "hugolib/site_benchmark_new_test.go::BenchmarkSiteNew::Regular_Tags_and_categories", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTaxonomiesGetTerms::pages_100", - "uri": "hugolib/taxonomy_test.go::BenchmarkTaxonomiesGetTerms::pages_100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTaxonomiesGetTerms::pages_1000", - "uri": "hugolib/taxonomy_test.go::BenchmarkTaxonomiesGetTerms::pages_1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTaxonomiesGetTerms::pages_10000", - "uri": "hugolib/taxonomy_test.go::BenchmarkTaxonomiesGetTerms::pages_10000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTaxonomiesGetTerms::pages_20000", - "uri": "hugolib/taxonomy_test.go::BenchmarkTaxonomiesGetTerms::pages_20000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkCSSEscaper", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkCSSEscaper", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCSSEscaperNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkCSSEscaperNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCSSValueFilter", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkCSSValueFilter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCSSValueFilterOk", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkCSSValueFilterOk", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkDecodeCSS", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkDecodeCSS", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkDecodeCSSNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/css_test.go::BenchmarkDecodeCSSNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkEscapedExecute", - "uri": "tpl/internal/go_templates/htmltemplate/escape_test.go::BenchmarkEscapedExecute", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHTMLNospaceEscaper", - "uri": "tpl/internal/go_templates/htmltemplate/html_test.go::BenchmarkHTMLNospaceEscaper", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHTMLNospaceEscaperNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/html_test.go::BenchmarkHTMLNospaceEscaperNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSRegexpEscaper", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSRegexpEscaper", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSRegexpEscaperNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSRegexpEscaperNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSStrEscaper", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSStrEscaper", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSStrEscaperNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSStrEscaperNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSValEscaperWithNum", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSValEscaperWithNum", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSValEscaperWithObj", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSValEscaperWithObj", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSValEscaperWithObjNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSValEscaperWithObjNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSValEscaperWithStr", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSValEscaperWithStr", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkJSValEscaperWithStrNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/js_test.go::BenchmarkJSValEscaperWithStrNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSrcsetFilter", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkSrcsetFilter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSrcsetFilterNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkSrcsetFilterNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStripTags", - "uri": "tpl/internal/go_templates/htmltemplate/html_test.go::BenchmarkStripTags", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStripTagsNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/html_test.go::BenchmarkStripTagsNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTemplateSpecialTags", - "uri": "tpl/internal/go_templates/htmltemplate/transition_test.go::BenchmarkTemplateSpecialTags", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkURLEscaper", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkURLEscaper", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkURLEscaperNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkURLEscaperNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkURLNormalizer", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkURLNormalizer", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkURLNormalizerNoSpecials", - "uri": "tpl/internal/go_templates/htmltemplate/url_test.go::BenchmarkURLNormalizerNoSpecials", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkCodeblocks::Default", - "uri": "markup/goldmark/goldmark_integration_test.go::BenchmarkCodeblocks::Default", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCodeblocks::Hook_no_higlight", - "uri": "markup/goldmark/goldmark_integration_test.go::BenchmarkCodeblocks::Hook_no_higlight", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkRenderHooks", - "uri": "markup/goldmark/goldmark_integration_test.go::BenchmarkRenderHooks", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkCollator::Para", - "uri": "langs/language_test.go::BenchmarkCollator::Para", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCollator::Single", - "uri": "langs/language_test.go::BenchmarkCollator::Single", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkCompareDescriptors", - "uri": "tpl/tplimpl/templatedescriptor_test.go::BenchmarkCompareDescriptors", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkCompileRegexp", - "uri": "common/hstrings/strings_test.go::BenchmarkCompileRegexp", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetOrCompileRegexp", - "uri": "common/hstrings/strings_test.go::BenchmarkGetOrCompileRegexp", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkDecodeExif", - "uri": "resources/images/exif/exif_test.go::BenchmarkDecodeExif", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkDecodeYAMLToMap", - "uri": "parser/metadecoders/decoder_test.go::BenchmarkDecodeYAMLToMap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStringifyMapKeysIntegers", - "uri": "parser/metadecoders/decoder_test.go::BenchmarkStringifyMapKeysIntegers", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStringifyMapKeysStringsOnlyInterfaceMaps", - "uri": "parser/metadecoders/decoder_test.go::BenchmarkStringifyMapKeysStringsOnlyInterfaceMaps", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStringifyMapKeysStringsOnlyStringMaps", - "uri": "parser/metadecoders/decoder_test.go::BenchmarkStringifyMapKeysStringsOnlyStringMaps", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkDefaultConfigProvider::Custom", - "uri": "config/defaultConfigProvider_test.go::BenchmarkDefaultConfigProvider::Custom", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkElementsCollectorWriter", - "uri": "publisher/htmlElementsCollector_test.go::BenchmarkElementsCollectorWriter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkElementsCollectorWriterPre", - "uri": "publisher/htmlElementsCollector_test.go::BenchmarkElementsCollectorWriterPre", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkExecuteGreet", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteGreet", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkExecuteGreetPara", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteGreetPara", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkExecuteKatex", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteKatex", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkExecuteKatexPara::PoolSize1", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteKatexPara::PoolSize1", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkExecuteKatexPara::PoolSize16", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteKatexPara::PoolSize16", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkExecuteKatexPara::PoolSize8", - "uri": "internal/warpc/warpc_test.go::BenchmarkExecuteKatexPara::PoolSize8", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkKatexStartStop::PoolSize1", - "uri": "internal/warpc/warpc_test.go::BenchmarkKatexStartStop::PoolSize1", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkKatexStartStop::PoolSize16", - "uri": "internal/warpc/warpc_test.go::BenchmarkKatexStartStop::PoolSize16", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkKatexStartStop::PoolSize8", - "uri": "internal/warpc/warpc_test.go::BenchmarkKatexStartStop::PoolSize8", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkExecuteWithContext", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkExecuteWithContext", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkLookupPagesLayout::Single_root", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkLookupPagesLayout::Single_root", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkLookupPagesLayout::Single_sub_folder", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkLookupPagesLayout::Single_sub_folder", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkLookupPartial", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkLookupPartial", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkLookupShortcode::nestedpage", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkLookupShortcode::nestedpage", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkLookupShortcode::toplevelpage", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkLookupShortcode::toplevelpage", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkNewTemplateStore", - "uri": "tpl/tplimpl/templatestore_integration_test.go::BenchmarkNewTemplateStore", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkFinder::Find_none", - "uri": "identity/finder_test.go::BenchmarkFinder::Find_none", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkFinder::Find_one", - "uri": "identity/finder_test.go::BenchmarkFinder::Find_one", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Add_duplicates", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Add_duplicates", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Add_unique", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Add_unique", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Nop_Anonymous", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Nop_Anonymous", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Nop_StringIdentity_const", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Nop_StringIdentity_const", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Nop_StringIdentity_const_other_package", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Nop_StringIdentity_const_other_package", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Nop_StringIdentity_var", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Nop_StringIdentity_var", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::Nop_pointer_identity", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::Nop_pointer_identity", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIdentityManager::identity.NewManager", - "uri": "identity/identity_test.go::BenchmarkIdentityManager::identity.NewManager", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIsNotDependent::Nested_not_found_10_5", - "uri": "identity/identity_test.go::BenchmarkIsNotDependent::Nested_not_found_10_5", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkGetGlob::Default_cache", - "uri": "hugofs/glob/glob_test.go::BenchmarkGetGlob::Default_cache", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetGlob::Filenames_cache,_lowercase_searches", - "uri": "hugofs/glob/glob_test.go::BenchmarkGetGlob::Filenames_cache,_lowercase_searches", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetGlob::Filenames_cache,_mixed_case_searches", - "uri": "hugofs/glob/glob_test.go::BenchmarkGetGlob::Filenames_cache,_mixed_case_searches", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetGlob::GetGlob", - "uri": "hugofs/glob/glob_test.go::BenchmarkGetGlob::GetGlob", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkGetMethodByName", - "uri": "common/hreflect/helpers_test.go::BenchmarkGetMethodByName", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkGetMethodByNamePara", - "uri": "common/hreflect/helpers_test.go::BenchmarkGetMethodByNamePara", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIsContextType::background", - "uri": "common/hreflect/helpers_test.go::BenchmarkIsContextType::background", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIsContextType::value", - "uri": "common/hreflect/helpers_test.go::BenchmarkIsContextType::value", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkIsTruthFul", - "uri": "common/hreflect/helpers_test.go::BenchmarkIsTruthFul", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHasShortcode::Match", - "uri": "parser/pageparser/pageparser_test.go::BenchmarkHasShortcode::Match", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHasShortcode::NoMatch", - "uri": "parser/pageparser/pageparser_test.go::BenchmarkHasShortcode::NoMatch", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkParse", - "uri": "parser/pageparser/pageparser_test.go::BenchmarkParse", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkShortcodeLexer", - "uri": "parser/pageparser/pageparser_shortcode_test.go::BenchmarkShortcodeLexer", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHash", - "uri": "hugolib/pagesfromdata/pagesfromgotmpl_test.go::BenchmarkHash", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHashImage", - "uri": "resources/resource_test.go::BenchmarkHashImage", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHashMap", - "uri": "common/hashing/hashing_test.go::BenchmarkHashMap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHashString::n112", - "uri": "common/hashing/hashing_test.go::BenchmarkHashString::n112", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHashString::n1792", - "uri": "common/hashing/hashing_test.go::BenchmarkHashString::n1792", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHashString::n28", - "uri": "common/hashing/hashing_test.go::BenchmarkHashString::n28", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHashString::n448", - "uri": "common/hashing/hashing_test.go::BenchmarkHashString::n448", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkHashString::n7168", - "uri": "common/hashing/hashing_test.go::BenchmarkHashString::n7168", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXXHashFromReader", - "uri": "common/hashing/hashing_test.go::BenchmarkXXHashFromReader", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXXHashFromString", - "uri": "common/hashing/hashing_test.go::BenchmarkXXHashFromString", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXXHashFromStringHexEncoded", - "uri": "common/hashing/hashing_test.go::BenchmarkXXHashFromStringHexEncoded", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHashingFs", - "uri": "hugofs/hashing_fs_test.go::BenchmarkHashingFs", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk", - "uri": "hugofs/walk_test.go::BenchmarkWalk", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkHowSimilar", - "uri": "metrics/metrics_test.go::BenchmarkHowSimilar", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkI18nTranslate::all-present", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::all-present", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::argument-float", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::argument-float", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::context-provided", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::context-provided", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::dotted-bare-key", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::dotted-bare-key", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::file-missing", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::file-missing", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::known-language-missing-plural", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::known-language-missing-plural", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::lang-with-hyphen", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::lang-with-hyphen", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::missing", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::missing", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::present-in-current", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::present-in-current", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::present-in-default", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::present-in-default", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-many", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-many", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-many-dot", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-many-dot", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-map-many", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-map-many", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-map-one", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-map-one", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-one", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-one", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::readingTime-string-one", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::readingTime-string-one", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::same-id-and-translation", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::same-id-and-translation", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::same-id-and-translation-default", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::same-id-and-translation-default", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::unknown-language-code", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::unknown-language-code", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkI18nTranslate::unknown-language-codes", - "uri": "langs/i18n/i18n_test.go::BenchmarkI18nTranslate::unknown-language-codes", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkImageExif::Cold_cache", - "uri": "resources/image_test.go::BenchmarkImageExif::Cold_cache", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkImageExif::Cold_cache,_10", - "uri": "resources/image_test.go::BenchmarkImageExif::Cold_cache,_10", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkImageExif::Warm_cache", - "uri": "resources/image_test.go::BenchmarkImageExif::Warm_cache", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkResizeParallel", - "uri": "resources/image_test.go::BenchmarkResizeParallel", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkInWithCaching", - "uri": "tpl/time/time_test.go::BenchmarkInWithCaching", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkInWithoutCaching", - "uri": "tpl/time/time_test.go::BenchmarkInWithoutCaching", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkIncludeCached", - "uri": "tpl/partials/partials_integration_test.go::BenchmarkIncludeCached", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkListString", - "uri": "tpl/internal/go_templates/texttemplate/parse/parse_test.go::BenchmarkListString", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkParseLarge", - "uri": "tpl/internal/go_templates/texttemplate/parse/parse_test.go::BenchmarkParseLarge", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkVariableString", - "uri": "tpl/internal/go_templates/texttemplate/parse/parse_test.go::BenchmarkVariableString", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkLiveReloadInject", - "uri": "transform/livereloadinject/livereloadinject_test.go::BenchmarkLiveReloadInject", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkLoad", - "uri": "config/allconfig/load_test.go::BenchmarkLoad", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkMerge", - "uri": "tpl/collections/merge_test.go::BenchmarkMerge", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkQuerify", - "uri": "tpl/collections/querify_test.go::BenchmarkQuerify", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkQuerifyMap", - "uri": "tpl/collections/querify_test.go::BenchmarkQuerifyMap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkQuerifySlice", - "uri": "tpl/collections/querify_test.go::BenchmarkQuerifySlice", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSortMap", - "uri": "tpl/collections/sort_test.go::BenchmarkSortMap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWhereMap", - "uri": "tpl/collections/where_test.go::BenchmarkWhereMap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWhereOps::eq", - "uri": "tpl/collections/where_test.go::BenchmarkWhereOps::eq", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWhereOps::like", - "uri": "tpl/collections/where_test.go::BenchmarkWhereOps::like", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWhereOps::ne", - "uri": "tpl/collections/where_test.go::BenchmarkWhereOps::ne", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkPageCache", - "uri": "resources/page/pages_cache_test.go::BenchmarkPageCache", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPermalinkExpand", - "uri": "resources/page/permalinks_test.go::BenchmarkPermalinkExpand", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByDate-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByDate-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByDate-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByDate-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByDate-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByDate-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByDate-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByDate-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByPublishDate-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByPublishDate-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByPublishDate-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByPublishDate-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByPublishDate-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByPublishDate-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByPublishDate-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByPublishDate-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle_Linear-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle_Linear-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle_Linear-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle_Linear-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle_Linear-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle_Linear-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByTitle_Linear-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByTitle_Linear-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight.Reverse-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight.Reverse-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight.Reverse-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight.Reverse-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight.Reverse-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight.Reverse-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::ByWeight.Reverse-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::ByWeight.Reverse-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::Shuffled-100", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::Shuffled-100", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::Shuffled-1000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::Shuffled-1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::Shuffled-500", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::Shuffled-500", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSearchPage::Shuffled-5000", - "uri": "resources/page/pages_sort_search_test.go::BenchmarkSearchPage::Shuffled-5000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSortByWeightAndReverse", - "uri": "resources/page/pages_sort_test.go::BenchmarkSortByWeightAndReverse", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSummaryFromHTML", - "uri": "resources/page/page_markup_test.go::BenchmarkSummaryFromHTML", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSummaryFromHTMLWithDivider", - "uri": "resources/page/page_markup_test.go::BenchmarkSummaryFromHTMLWithDivider", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkParseIdentity", - "uri": "common/paths/pathparser_test.go::BenchmarkParseIdentity", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSanitize::All_allowed", - "uri": "common/paths/path_test.go::BenchmarkSanitize::All_allowed", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSanitize::Spaces", - "uri": "common/paths/path_test.go::BenchmarkSanitize::Spaces", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkPoller::Check_for_changes_in_dir", - "uri": "watcher/filenotify/poller_test.go::BenchmarkPoller::Check_for_changes_in_dir", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkPoller::Check_for_changes_in_file", - "uri": "watcher/filenotify/poller_test.go::BenchmarkPoller::Check_for_changes_in_file", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkRelatedMatchesIn", - "uri": "related/inverted_index_test.go::BenchmarkRelatedMatchesIn", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkRelatedNewIndex::all", - "uri": "related/inverted_index_test.go::BenchmarkRelatedNewIndex::all", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkRelatedNewIndex::singles", - "uri": "related/inverted_index_test.go::BenchmarkRelatedNewIndex::singles", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkRelatedSite", - "uri": "related/related_integration_test.go::BenchmarkRelatedSite", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkSanitizeAnchorName", - "uri": "markup/goldmark/autoid_test.go::BenchmarkSanitizeAnchorName", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSanitizeAnchorNameAsciiOnly", - "uri": "markup/goldmark/autoid_test.go::BenchmarkSanitizeAnchorNameAsciiOnly", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSanitizeAnchorNameBlackfriday", - "uri": "markup/goldmark/autoid_test.go::BenchmarkSanitizeAnchorNameBlackfriday", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkSanitizeAnchorNameString", - "uri": "markup/goldmark/autoid_test.go::BenchmarkSanitizeAnchorNameString", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkScratchGet", - "uri": "common/maps/scratch_test.go::BenchmarkScratchGet", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkSegmentsMatch", - "uri": "hugolib/segments/segments_test.go::BenchmarkSegmentsMatch", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkStringSort::LessStrings", - "uri": "compare/compare_strings_test.go::BenchmarkStringSort::LessStrings", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkTimeFormatter::Localized", - "uri": "common/htime/time_test.go::BenchmarkTimeFormatter::Localized", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTimeFormatter::Localized_Custom", - "uri": "common/htime/time_test.go::BenchmarkTimeFormatter::Localized_Custom", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTimeFormatter::Native", - "uri": "common/htime/time_test.go::BenchmarkTimeFormatter::Native", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkToc::Build", - "uri": "markup/tableofcontents/tableofcontents_test.go::BenchmarkToc::Build", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkToc::ToHTML", - "uri": "markup/tableofcontents/tableofcontents_test.go::BenchmarkToc::ToHTML", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkTreeInsert::1000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkTreeInsert::1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTreeInsert::10000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkTreeInsert::10000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTreeInsert::100000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkTreeInsert::100000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTreeInsert::300000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkTreeInsert::300000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_all_dimensions_1000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_all_dimensions_1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_all_dimensions_10000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_all_dimensions_10000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_all_dimensions_100000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_all_dimensions_100000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_one_dimension_1000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_one_dimension_1000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_one_dimension_10000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_one_dimension_10000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkWalk::Walk_one_dimension_100000", - "uri": "hugolib/doctree/nodeshiftree_test.go::BenchmarkWalk::Walk_one_dimension_100000", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkTruncate::Plain_text", - "uri": "tpl/strings/truncate_test.go::BenchmarkTruncate::Plain_text", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkTruncate::With_link", - "uri": "tpl/strings/truncate_test.go::BenchmarkTruncate::With_link", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkTypeOps", - "uri": "media/mediaType_test.go::BenchmarkTypeOps", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkVisitLinesAfter", - "uri": "common/text/transform_test.go::BenchmarkVisitLinesAfter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkWrap", - "uri": "markup/goldmark/hugocontext/hugocontext_test.go::BenchmarkWrap", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkXxHash::fnv32a_43", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::fnv32a_43", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXxHash::fnv32a_4300", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::fnv32a_4300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXxHash::mdb5_43", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::mdb5_43", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXxHash::mdb5_4300", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::mdb5_4300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXxHash::xxHash_43", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::xxHash_43", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkXxHash::xxHash_4300", - "uri": "tpl/hash/hash_test.go::BenchmarkXxHash::xxHash_4300", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - } -] diff --git a/go-runner/testdata/projects/hugo b/go-runner/testdata/projects/hugo deleted file mode 160000 index 84dd495f..00000000 --- a/go-runner/testdata/projects/hugo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 84dd495f2b9e9a47ad2cead256698dcc15152aa7 From 7771ea7dd01306039d7ed38b888e6362f0718241 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:17:12 +0100 Subject: [PATCH 08/13] chore(go-runner): remove caddy test It's unstable and panics in one of the benchmarks, which makes the overall test fail. We shouldn't try to handle this, it has to be fixed upstream. --- .gitmodules | 3 - go-runner/src/integration_tests.rs | 3 - ...tests__assert_results_snapshots@caddy.snap | 107 ------------------ go-runner/testdata/projects/caddy | 1 - 4 files changed, 114 deletions(-) delete mode 100644 go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@caddy.snap delete mode 160000 go-runner/testdata/projects/caddy diff --git a/.gitmodules b/.gitmodules index 72f72309..8247f2f2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,9 +19,6 @@ [submodule "go-runner/testdata/projects/cli-runtime"] path = go-runner/testdata/projects/cli-runtime url = https://github.com/kubernetes/cli-runtime.git -[submodule "go-runner/testdata/projects/caddy"] - path = go-runner/testdata/projects/caddy - url = https://github.com/caddyserver/caddy [submodule "go-runner/testdata/projects/quic-go"] path = go-runner/testdata/projects/quic-go url = https://github.com/quic-go/quic-go diff --git a/go-runner/src/integration_tests.rs b/go-runner/src/integration_tests.rs index 58f92731..d47a9acf 100644 --- a/go-runner/src/integration_tests.rs +++ b/go-runner/src/integration_tests.rs @@ -63,9 +63,6 @@ fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { } #[rstest] -// The 'BenchmarkMatchExpressionMatch/boolean_matches_succeed_for_placeholder_http.request.tls.client.subject-16' benchmark currently -// panics, which causes the binary (which contains more benchmarks) to exit. Has to be fixed within Caddy. -#[case::caddy("caddy")] #[case::fzf("fzf")] #[case::opentelemetry_go("opentelemetry-go")] #[case::golang_benchmarks("golang-benchmarks")] diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@caddy.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@caddy.snap deleted file mode 100644 index bd8919a4..00000000 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@caddy.snap +++ /dev/null @@ -1,107 +0,0 @@ ---- -source: go-runner/src/integration_tests.rs -expression: results ---- -[ - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkLoad", - "uri": "admin_test.go::BenchmarkLoad", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplacer::escaped_placeholder", - "uri": "replacer_test.go::BenchmarkReplacer::escaped_placeholder", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplacer::int_replacement", - "uri": "replacer_test.go::BenchmarkReplacer::int_replacement", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplacer::no_placeholder", - "uri": "replacer_test.go::BenchmarkReplacer::no_placeholder", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplacer::placeholder", - "uri": "replacer_test.go::BenchmarkReplacer::placeholder", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkReplacer::string_replacement", - "uri": "replacer_test.go::BenchmarkReplacer::string_replacement", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkOpenResponseWriter", - "uri": "modules/caddyhttp/encode/encode_test.go::BenchmarkOpenResponseWriter", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - } -] diff --git a/go-runner/testdata/projects/caddy b/go-runner/testdata/projects/caddy deleted file mode 160000 index 551f7937..00000000 --- a/go-runner/testdata/projects/caddy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 551f793700fe1550845c824470b623fd1aa03d36 From baaa2aefdbb73f2ba725deeab4e2da9b19bc2dfd Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 11:26:49 +0100 Subject: [PATCH 09/13] fix(integration-tests): sort snapshots using URI to have deterministic ordering It's possible for two benchmarks to have the same name, which causes non-deterministic ordering in the benchmarks. --- go-runner/src/integration_tests.rs | 4 +- ...s_snapshots@example-with-test-package.snap | 16 +- ...sts__assert_results_snapshots@example.snap | 122 ++-- ...t_results_snapshots@golang-benchmarks.snap | 638 +++++++++--------- ...rt_results_snapshots@opentelemetry-go.snap | 154 ++--- ...sts__assert_results_snapshots@quic-go.snap | 512 +++++++------- ...n_tests__assert_results_snapshots@zap.snap | 136 ++-- ...sts__assert_results_snapshots@zerolog.snap | 532 +++++++-------- 8 files changed, 1057 insertions(+), 1057 deletions(-) diff --git a/go-runner/src/integration_tests.rs b/go-runner/src/integration_tests.rs index d47a9acf..d82d642b 100644 --- a/go-runner/src/integration_tests.rs +++ b/go-runner/src/integration_tests.rs @@ -24,7 +24,7 @@ fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { .sorted_by_cached_key(|r| { r.benchmarks .iter() - .map(|b| b.metadata.name.clone()) + .map(|b| b.metadata.uri.clone()) .sorted() .join(";") }) @@ -44,7 +44,7 @@ fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { results.sort_by_cached_key(|r| { r.benchmarks .iter() - .map(|b| b.metadata.name.clone()) + .map(|b| b.metadata.uri.clone()) .sorted() .join(";") }); diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap index 537f7c50..aa1dc859 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example-with-test-package.snap @@ -14,8 +14,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkAdd", - "uri": "go-runner/testdata/projects/example-with-test-package/math_test.go::BenchmarkAdd", + "name": "BenchmarkFibonacci10", + "uri": "go-runner/testdata/projects/example-with-test-package/fib/fib_test.go::BenchmarkFibonacci10", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -25,8 +25,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMultiply", - "uri": "go-runner/testdata/projects/example-with-test-package/math_test.go::BenchmarkMultiply", + "name": "BenchmarkFibonacci20", + "uri": "go-runner/testdata/projects/example-with-test-package/fib/fib_test.go::BenchmarkFibonacci20", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -82,8 +82,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkFibonacci10", - "uri": "go-runner/testdata/projects/example-with-test-package/fib/fib_test.go::BenchmarkFibonacci10", + "name": "BenchmarkAdd", + "uri": "go-runner/testdata/projects/example-with-test-package/math_test.go::BenchmarkAdd", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -93,8 +93,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFibonacci20", - "uri": "go-runner/testdata/projects/example-with-test-package/fib/fib_test.go::BenchmarkFibonacci20", + "name": "BenchmarkMultiply", + "uri": "go-runner/testdata/projects/example-with-test-package/math_test.go::BenchmarkMultiply", "config": { "warmup_time_ns": null, "min_round_time_ns": null, diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example.snap index 6330f1f4..b93d29f2 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@example.snap @@ -14,30 +14,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkBufferRead", - "uri": "example/sub-packages/buffer_test.go::BenchmarkBufferRead", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkBufferWrite", - "uri": "example/sub-packages/buffer_test.go::BenchmarkBufferWrite", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkCounterWithMutex", - "uri": "example/sub-packages/buffer_test.go::BenchmarkCounterWithMutex", + "name": "BenchmarkQuicktest", + "uri": "example/compat/quicktest_test.go::BenchmarkQuicktest", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -47,8 +25,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFSTestFS", - "uri": "example/sub-packages/buffer_test.go::BenchmarkFSTestFS", + "name": "BenchmarkTestifyWithNew", + "uri": "example/compat/testify_test.go::BenchmarkTestifyWithNew", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -58,8 +36,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkIOTestReader", - "uri": "example/sub-packages/buffer_test.go::BenchmarkIOTestReader", + "name": "BenchmarkTestifyWithT", + "uri": "example/compat/testify_test.go::BenchmarkTestifyWithT", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -69,31 +47,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkWriterFunc", - "uri": "example/sub-packages/buffer_test.go::BenchmarkWriterFunc", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkExample", - "uri": "example/very/nested/module/example_test.go::BenchmarkExample", + "name": "BenchmarkWithSlogAssert", + "uri": "example/compat/slogassert_test.go::BenchmarkWithSlogAssert", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -293,8 +248,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkQuicktest", - "uri": "example/compat/quicktest_test.go::BenchmarkQuicktest", + "name": "BenchmarkBufferRead", + "uri": "example/sub-packages/buffer_test.go::BenchmarkBufferRead", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -304,8 +259,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTestifyWithNew", - "uri": "example/compat/testify_test.go::BenchmarkTestifyWithNew", + "name": "BenchmarkBufferWrite", + "uri": "example/sub-packages/buffer_test.go::BenchmarkBufferWrite", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -315,8 +270,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTestifyWithT", - "uri": "example/compat/testify_test.go::BenchmarkTestifyWithT", + "name": "BenchmarkCounterWithMutex", + "uri": "example/sub-packages/buffer_test.go::BenchmarkCounterWithMutex", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -326,8 +281,30 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkWithSlogAssert", - "uri": "example/compat/slogassert_test.go::BenchmarkWithSlogAssert", + "name": "BenchmarkFSTestFS", + "uri": "example/sub-packages/buffer_test.go::BenchmarkFSTestFS", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkIOTestReader", + "uri": "example/sub-packages/buffer_test.go::BenchmarkIOTestReader", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkWriterFunc", + "uri": "example/sub-packages/buffer_test.go::BenchmarkWriterFunc", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -503,5 +480,28 @@ expression: results "stats": "[stats]" } ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkExample", + "uri": "example/very/nested/module/example_test.go::BenchmarkExample", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] } ] diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@golang-benchmarks.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@golang-benchmarks.snap index 860982ab..7dffc12c 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@golang-benchmarks.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@golang-benchmarks.snap @@ -14,8 +14,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkAdler32", - "uri": "hash/hash_test.go::BenchmarkAdler32", + "name": "BenchmarkBase64decode", + "uri": "base64/base64_test.go::BenchmarkBase64decode", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -25,8 +25,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBCryptCost10", - "uri": "hash/hash_test.go::BenchmarkBCryptCost10", + "name": "BenchmarkBase64regex", + "uri": "base64/base64_test.go::BenchmarkBase64regex", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -34,10 +34,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkBCryptCost16", - "uri": "hash/hash_test.go::BenchmarkBCryptCost16", + "name": "BenchmarkFulltextParse", + "uri": "between/between_test.go::BenchmarkFulltextParse", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -47,8 +59,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBCryptCost4", - "uri": "hash/hash_test.go::BenchmarkBCryptCost4", + "name": "BenchmarkFulltextRegEx", + "uri": "between/between_test.go::BenchmarkFulltextRegEx", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -58,8 +70,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBlake2b256", - "uri": "hash/hash_test.go::BenchmarkBlake2b256", + "name": "BenchmarkNumberParse", + "uri": "between/between_test.go::BenchmarkNumberParse", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -69,8 +81,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBlake2b512", - "uri": "hash/hash_test.go::BenchmarkBlake2b512", + "name": "BenchmarkNumberRegEx", + "uri": "between/between_test.go::BenchmarkNumberRegEx", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -78,10 +90,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkBlake3256", - "uri": "hash/hash_test.go::BenchmarkBlake3256", + "name": "BenchmarkEqualFold", + "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkEqualFold", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -91,8 +115,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkCRC32", - "uri": "hash/hash_test.go::BenchmarkCRC32", + "name": "BenchmarkToLower", + "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkToLower", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -102,8 +126,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkCRC64ECMA", - "uri": "hash/hash_test.go::BenchmarkCRC64ECMA", + "name": "BenchmarkToUpper", + "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkToUpper", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -111,10 +135,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkCRC64ISO", - "uri": "hash/hash_test.go::BenchmarkCRC64ISO", + "name": "BenchmarkConcat::Buffer", + "uri": "concat/concat_test.go::BenchmarkConcat::Buffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -124,8 +160,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFnv128", - "uri": "hash/hash_test.go::BenchmarkFnv128", + "name": "BenchmarkConcat::Builder", + "uri": "concat/concat_test.go::BenchmarkConcat::Builder", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -135,8 +171,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFnv128a", - "uri": "hash/hash_test.go::BenchmarkFnv128a", + "name": "BenchmarkConcat::String", + "uri": "concat/concat_test.go::BenchmarkConcat::String", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -146,8 +182,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFnv32", - "uri": "hash/hash_test.go::BenchmarkFnv32", + "name": "BenchmarkConcatBuffer", + "uri": "concat/concat_test.go::BenchmarkConcatBuffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -157,8 +193,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFnv32a", - "uri": "hash/hash_test.go::BenchmarkFnv32a", + "name": "BenchmarkConcatBuilder", + "uri": "concat/concat_test.go::BenchmarkConcatBuilder", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -168,8 +204,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFnv64", - "uri": "hash/hash_test.go::BenchmarkFnv64", + "name": "BenchmarkConcatString", + "uri": "concat/concat_test.go::BenchmarkConcatString", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -177,10 +213,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkFnv64a", - "uri": "hash/hash_test.go::BenchmarkFnv64a", + "name": "BenchmarkCompileMatch", + "uri": "contains/contains_test.go::BenchmarkCompileMatch", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -190,8 +238,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMD4", - "uri": "hash/hash_test.go::BenchmarkMD4", + "name": "BenchmarkCompileMatchNot", + "uri": "contains/contains_test.go::BenchmarkCompileMatchNot", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -201,8 +249,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMD5", - "uri": "hash/hash_test.go::BenchmarkMD5", + "name": "BenchmarkContains", + "uri": "contains/contains_test.go::BenchmarkContains", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -212,8 +260,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMMH3", - "uri": "hash/hash_test.go::BenchmarkMMH3", + "name": "BenchmarkContainsBytes", + "uri": "contains/contains_test.go::BenchmarkContainsBytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -223,8 +271,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRIPEMD160", - "uri": "hash/hash_test.go::BenchmarkRIPEMD160", + "name": "BenchmarkContainsBytesNot", + "uri": "contains/contains_test.go::BenchmarkContainsBytesNot", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -234,8 +282,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA1", - "uri": "hash/hash_test.go::BenchmarkSHA1", + "name": "BenchmarkContainsMethods::Bytes.Contains", + "uri": "contains/contains_test.go::BenchmarkContainsMethods::Bytes.Contains", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -245,8 +293,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA224", - "uri": "hash/hash_test.go::BenchmarkSHA224", + "name": "BenchmarkContainsMethods::RegexMatch", + "uri": "contains/contains_test.go::BenchmarkContainsMethods::RegexMatch", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -256,8 +304,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA256", - "uri": "hash/hash_test.go::BenchmarkSHA256", + "name": "BenchmarkContainsMethods::RegexMatchString", + "uri": "contains/contains_test.go::BenchmarkContainsMethods::RegexMatchString", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -267,8 +315,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA256Parallel", - "uri": "hash/hash_test.go::BenchmarkSHA256Parallel", + "name": "BenchmarkContainsMethods::Strings.Contains", + "uri": "contains/contains_test.go::BenchmarkContainsMethods::Strings.Contains", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -278,8 +326,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA3256", - "uri": "hash/hash_test.go::BenchmarkSHA3256", + "name": "BenchmarkContainsNot", + "uri": "contains/contains_test.go::BenchmarkContainsNot", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -289,8 +337,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA3512", - "uri": "hash/hash_test.go::BenchmarkSHA3512", + "name": "BenchmarkMatch", + "uri": "contains/contains_test.go::BenchmarkMatch", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -300,8 +348,31 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA384", - "uri": "hash/hash_test.go::BenchmarkSHA384", + "name": "BenchmarkMatchNot", + "uri": "contains/contains_test.go::BenchmarkMatchNot", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkEmbed", + "uri": "embed/embed_test.go::BenchmarkEmbed", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -311,8 +382,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSHA512", - "uri": "hash/hash_test.go::BenchmarkSHA512", + "name": "BenchmarkIoutilReadFile", + "uri": "embed/embed_test.go::BenchmarkIoutilReadFile", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -322,8 +393,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkWhirlpool", - "uri": "hash/hash_test.go::BenchmarkWhirlpool", + "name": "BenchmarkReadFile", + "uri": "embed/embed_test.go::BenchmarkReadFile", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -345,8 +416,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkBase64decode", - "uri": "base64/base64_test.go::BenchmarkBase64decode", + "name": "BenchmarkFloodFillBFS", + "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillBFS", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -356,8 +427,30 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkBase64regex", - "uri": "base64/base64_test.go::BenchmarkBase64regex", + "name": "BenchmarkFloodFillDFS", + "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillDFS", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkFloodFillRecursive", + "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillRecursive", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkFloodFillStack4Way", + "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillStack4Way", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -379,8 +472,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkCompileMatch", - "uri": "contains/contains_test.go::BenchmarkCompileMatch", + "name": "BenchmarkForMap", + "uri": "foreach/foreach_test.go::BenchmarkForMap", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -390,8 +483,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkCompileMatchNot", - "uri": "contains/contains_test.go::BenchmarkCompileMatchNot", + "name": "BenchmarkRangeMap", + "uri": "foreach/foreach_test.go::BenchmarkRangeMap", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -401,8 +494,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContains", - "uri": "contains/contains_test.go::BenchmarkContains", + "name": "BenchmarkRangeSlice", + "uri": "foreach/foreach_test.go::BenchmarkRangeSlice", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -412,8 +505,31 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsBytes", - "uri": "contains/contains_test.go::BenchmarkContainsBytes", + "name": "BenchmarkRangeSliceKey", + "uri": "foreach/foreach_test.go::BenchmarkRangeSliceKey", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkAdler32", + "uri": "hash/hash_test.go::BenchmarkAdler32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -423,8 +539,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsBytesNot", - "uri": "contains/contains_test.go::BenchmarkContainsBytesNot", + "name": "BenchmarkBCryptCost10", + "uri": "hash/hash_test.go::BenchmarkBCryptCost10", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -434,8 +550,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsMethods::Bytes.Contains", - "uri": "contains/contains_test.go::BenchmarkContainsMethods::Bytes.Contains", + "name": "BenchmarkBCryptCost16", + "uri": "hash/hash_test.go::BenchmarkBCryptCost16", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -445,8 +561,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsMethods::RegexMatch", - "uri": "contains/contains_test.go::BenchmarkContainsMethods::RegexMatch", + "name": "BenchmarkBCryptCost4", + "uri": "hash/hash_test.go::BenchmarkBCryptCost4", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -456,8 +572,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsMethods::RegexMatchString", - "uri": "contains/contains_test.go::BenchmarkContainsMethods::RegexMatchString", + "name": "BenchmarkBlake2b256", + "uri": "hash/hash_test.go::BenchmarkBlake2b256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -467,8 +583,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsMethods::Strings.Contains", - "uri": "contains/contains_test.go::BenchmarkContainsMethods::Strings.Contains", + "name": "BenchmarkBlake2b512", + "uri": "hash/hash_test.go::BenchmarkBlake2b512", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -478,8 +594,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContainsNot", - "uri": "contains/contains_test.go::BenchmarkContainsNot", + "name": "BenchmarkBlake3256", + "uri": "hash/hash_test.go::BenchmarkBlake3256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -489,8 +605,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMatch", - "uri": "contains/contains_test.go::BenchmarkMatch", + "name": "BenchmarkCRC32", + "uri": "hash/hash_test.go::BenchmarkCRC32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -500,8 +616,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMatchNot", - "uri": "contains/contains_test.go::BenchmarkMatchNot", + "name": "BenchmarkCRC64ECMA", + "uri": "hash/hash_test.go::BenchmarkCRC64ECMA", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -509,22 +625,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkConcat::Buffer", - "uri": "concat/concat_test.go::BenchmarkConcat::Buffer", + "name": "BenchmarkCRC64ISO", + "uri": "hash/hash_test.go::BenchmarkCRC64ISO", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -534,8 +638,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConcat::Builder", - "uri": "concat/concat_test.go::BenchmarkConcat::Builder", + "name": "BenchmarkFnv128", + "uri": "hash/hash_test.go::BenchmarkFnv128", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -545,8 +649,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConcat::String", - "uri": "concat/concat_test.go::BenchmarkConcat::String", + "name": "BenchmarkFnv128a", + "uri": "hash/hash_test.go::BenchmarkFnv128a", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -556,8 +660,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConcatBuffer", - "uri": "concat/concat_test.go::BenchmarkConcatBuffer", + "name": "BenchmarkFnv32", + "uri": "hash/hash_test.go::BenchmarkFnv32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -567,8 +671,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConcatBuilder", - "uri": "concat/concat_test.go::BenchmarkConcatBuilder", + "name": "BenchmarkFnv32a", + "uri": "hash/hash_test.go::BenchmarkFnv32a", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -578,8 +682,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConcatString", - "uri": "concat/concat_test.go::BenchmarkConcatString", + "name": "BenchmarkFnv64", + "uri": "hash/hash_test.go::BenchmarkFnv64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -587,22 +691,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkCryptoRand", - "uri": "random/random_test.go::BenchmarkCryptoRand", + "name": "BenchmarkFnv64a", + "uri": "hash/hash_test.go::BenchmarkFnv64a", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -612,8 +704,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkCryptoRandBytes", - "uri": "random/random_test.go::BenchmarkCryptoRandBytes", + "name": "BenchmarkMD4", + "uri": "hash/hash_test.go::BenchmarkMD4", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -623,8 +715,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkCryptoRandString", - "uri": "random/random_test.go::BenchmarkCryptoRandString", + "name": "BenchmarkMD5", + "uri": "hash/hash_test.go::BenchmarkMD5", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -634,8 +726,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathRand", - "uri": "random/random_test.go::BenchmarkMathRand", + "name": "BenchmarkMMH3", + "uri": "hash/hash_test.go::BenchmarkMMH3", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -643,22 +735,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkEmbed", - "uri": "embed/embed_test.go::BenchmarkEmbed", + "name": "BenchmarkRIPEMD160", + "uri": "hash/hash_test.go::BenchmarkRIPEMD160", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -668,8 +748,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkIoutilReadFile", - "uri": "embed/embed_test.go::BenchmarkIoutilReadFile", + "name": "BenchmarkSHA1", + "uri": "hash/hash_test.go::BenchmarkSHA1", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -679,8 +759,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadFile", - "uri": "embed/embed_test.go::BenchmarkReadFile", + "name": "BenchmarkSHA224", + "uri": "hash/hash_test.go::BenchmarkSHA224", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -688,22 +768,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkEqualFold", - "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkEqualFold", + "name": "BenchmarkSHA256", + "uri": "hash/hash_test.go::BenchmarkSHA256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -713,8 +781,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkToLower", - "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkToLower", + "name": "BenchmarkSHA256Parallel", + "uri": "hash/hash_test.go::BenchmarkSHA256Parallel", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -724,8 +792,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkToUpper", - "uri": "caseinsensitivecompare/caseinsensitivecompare_test.go::BenchmarkToUpper", + "name": "BenchmarkSHA3256", + "uri": "hash/hash_test.go::BenchmarkSHA3256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -733,22 +801,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkFloodFillBFS", - "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillBFS", + "name": "BenchmarkSHA3512", + "uri": "hash/hash_test.go::BenchmarkSHA3512", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -758,8 +814,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFloodFillDFS", - "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillDFS", + "name": "BenchmarkSHA384", + "uri": "hash/hash_test.go::BenchmarkSHA384", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -769,8 +825,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFloodFillRecursive", - "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillRecursive", + "name": "BenchmarkSHA512", + "uri": "hash/hash_test.go::BenchmarkSHA512", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -780,8 +836,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkFloodFillStack4Way", - "uri": "floodfill/floodfill_test.go::BenchmarkFloodFillStack4Way", + "name": "BenchmarkWhirlpool", + "uri": "hash/hash_test.go::BenchmarkWhirlpool", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -803,8 +859,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkForMap", - "uri": "foreach/foreach_test.go::BenchmarkForMap", + "name": "BenchmarkMapIntIndex", + "uri": "index/index_test.go::BenchmarkMapIntIndex", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -814,8 +870,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRangeMap", - "uri": "foreach/foreach_test.go::BenchmarkRangeMap", + "name": "BenchmarkMapIntKeys", + "uri": "index/index_test.go::BenchmarkMapIntKeys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -825,8 +881,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRangeSlice", - "uri": "foreach/foreach_test.go::BenchmarkRangeSlice", + "name": "BenchmarkMapStringIndex", + "uri": "index/index_test.go::BenchmarkMapStringIndex", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -836,8 +892,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRangeSliceKey", - "uri": "foreach/foreach_test.go::BenchmarkRangeSliceKey", + "name": "BenchmarkMapStringKeys", + "uri": "index/index_test.go::BenchmarkMapStringKeys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -859,30 +915,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkFulltextParse", - "uri": "between/between_test.go::BenchmarkFulltextParse", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkFulltextRegEx", - "uri": "between/between_test.go::BenchmarkFulltextRegEx", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkNumberParse", - "uri": "between/between_test.go::BenchmarkNumberParse", + "name": "BenchmarkJsonMarshal", + "uri": "json/json_test.go::BenchmarkJsonMarshal", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -892,8 +926,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkNumberRegEx", - "uri": "between/between_test.go::BenchmarkNumberRegEx", + "name": "BenchmarkJsonUnmarshal", + "uri": "json/json_test.go::BenchmarkJsonUnmarshal", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -915,8 +949,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkHTMLTemplate", - "uri": "template/template_test.go::BenchmarkHTMLTemplate", + "name": "BenchmarkMathAtomicInt32", + "uri": "math/math_test.go::BenchmarkMathAtomicInt32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -926,8 +960,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRegExp", - "uri": "template/template_test.go::BenchmarkRegExp", + "name": "BenchmarkMathAtomicInt64", + "uri": "math/math_test.go::BenchmarkMathAtomicInt64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -937,31 +971,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTextTemplate", - "uri": "template/template_test.go::BenchmarkTextTemplate", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkJsonMarshal", - "uri": "json/json_test.go::BenchmarkJsonMarshal", + "name": "BenchmarkMathFloat32", + "uri": "math/math_test.go::BenchmarkMathFloat32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -971,8 +982,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkJsonUnmarshal", - "uri": "json/json_test.go::BenchmarkJsonUnmarshal", + "name": "BenchmarkMathFloat64", + "uri": "math/math_test.go::BenchmarkMathFloat64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -980,22 +991,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkMapIntIndex", - "uri": "index/index_test.go::BenchmarkMapIntIndex", + "name": "BenchmarkMathInt32", + "uri": "math/math_test.go::BenchmarkMathInt32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1005,8 +1004,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMapIntKeys", - "uri": "index/index_test.go::BenchmarkMapIntKeys", + "name": "BenchmarkMathInt64", + "uri": "math/math_test.go::BenchmarkMathInt64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1016,8 +1015,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMapStringIndex", - "uri": "index/index_test.go::BenchmarkMapStringIndex", + "name": "BenchmarkMathInt8", + "uri": "math/math_test.go::BenchmarkMathInt8", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1027,8 +1026,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMapStringKeys", - "uri": "index/index_test.go::BenchmarkMapStringKeys", + "name": "BenchmarkMathMutexInt", + "uri": "math/math_test.go::BenchmarkMathMutexInt", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1050,8 +1049,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkMatchString", - "uri": "regexp/regexp_test.go::BenchmarkMatchString", + "name": "BenchmarkParseBool", + "uri": "parse/parse_test.go::BenchmarkParseBool", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1061,8 +1060,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMatchStringCompiled", - "uri": "regexp/regexp_test.go::BenchmarkMatchStringCompiled", + "name": "BenchmarkParseFloat", + "uri": "parse/parse_test.go::BenchmarkParseFloat", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1072,8 +1071,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMatchStringGolibs", - "uri": "regexp/regexp_test.go::BenchmarkMatchStringGolibs", + "name": "BenchmarkParseInt", + "uri": "parse/parse_test.go::BenchmarkParseInt", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1095,19 +1094,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkMathAtomicInt32", - "uri": "math/math_test.go::BenchmarkMathAtomicInt32", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkMathAtomicInt64", - "uri": "math/math_test.go::BenchmarkMathAtomicInt64", + "name": "BenchmarkCryptoRand", + "uri": "random/random_test.go::BenchmarkCryptoRand", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1117,8 +1105,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathFloat32", - "uri": "math/math_test.go::BenchmarkMathFloat32", + "name": "BenchmarkCryptoRandBytes", + "uri": "random/random_test.go::BenchmarkCryptoRandBytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1128,8 +1116,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathFloat64", - "uri": "math/math_test.go::BenchmarkMathFloat64", + "name": "BenchmarkCryptoRandString", + "uri": "random/random_test.go::BenchmarkCryptoRandString", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1139,8 +1127,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathInt32", - "uri": "math/math_test.go::BenchmarkMathInt32", + "name": "BenchmarkMathRand", + "uri": "random/random_test.go::BenchmarkMathRand", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1148,10 +1136,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkMathInt64", - "uri": "math/math_test.go::BenchmarkMathInt64", + "name": "BenchmarkMatchString", + "uri": "regexp/regexp_test.go::BenchmarkMatchString", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1161,8 +1161,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathInt8", - "uri": "math/math_test.go::BenchmarkMathInt8", + "name": "BenchmarkMatchStringCompiled", + "uri": "regexp/regexp_test.go::BenchmarkMatchStringCompiled", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1172,8 +1172,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkMathMutexInt", - "uri": "math/math_test.go::BenchmarkMathMutexInt", + "name": "BenchmarkMatchStringGolibs", + "uri": "regexp/regexp_test.go::BenchmarkMatchStringGolibs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1195,8 +1195,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkParseBool", - "uri": "parse/parse_test.go::BenchmarkParseBool", + "name": "BenchmarkHTMLTemplate", + "uri": "template/template_test.go::BenchmarkHTMLTemplate", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1206,8 +1206,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseFloat", - "uri": "parse/parse_test.go::BenchmarkParseFloat", + "name": "BenchmarkRegExp", + "uri": "template/template_test.go::BenchmarkRegExp", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1217,8 +1217,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseInt", - "uri": "parse/parse_test.go::BenchmarkParseInt", + "name": "BenchmarkTextTemplate", + "uri": "template/template_test.go::BenchmarkTextTemplate", "config": { "warmup_time_ns": null, "min_round_time_ns": null, diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@opentelemetry-go.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@opentelemetry-go.snap index d62f03c8..608b8224 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@opentelemetry-go.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@opentelemetry-go.snap @@ -3,73 +3,6 @@ source: go-runner/src/integration_tests.rs expression: results --- [ - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkAsFloat64Slice", - "uri": "attribute/internal/attribute_test.go::BenchmarkAsFloat64Slice", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkBoolSliceValue", - "uri": "attribute/internal/attribute_test.go::BenchmarkBoolSliceValue", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkFloat64SliceValue", - "uri": "attribute/internal/attribute_test.go::BenchmarkFloat64SliceValue", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkInt64SliceValue", - "uri": "attribute/internal/attribute_test.go::BenchmarkInt64SliceValue", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkStringSliceValue", - "uri": "attribute/internal/attribute_test.go::BenchmarkStringSliceValue", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, { "creator": { "name": "codspeed-go", @@ -665,8 +598,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkExtract::BogusVersion", - "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::BogusVersion", + "name": "BenchmarkAsFloat64Slice", + "uri": "attribute/internal/attribute_test.go::BenchmarkAsFloat64Slice", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -676,8 +609,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkExtract::FutureAdditionalData", - "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::FutureAdditionalData", + "name": "BenchmarkBoolSliceValue", + "uri": "attribute/internal/attribute_test.go::BenchmarkBoolSliceValue", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -687,8 +620,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkExtract::Sampled", - "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::Sampled", + "name": "BenchmarkFloat64SliceValue", + "uri": "attribute/internal/attribute_test.go::BenchmarkFloat64SliceValue", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -698,8 +631,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInject::SampledSpanContext", - "uri": "propagation/trace_context_benchmark_test.go::BenchmarkInject::SampledSpanContext", + "name": "BenchmarkInt64SliceValue", + "uri": "attribute/internal/attribute_test.go::BenchmarkInt64SliceValue", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -709,8 +642,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInject::WithoutSpanContext", - "uri": "propagation/trace_context_benchmark_test.go::BenchmarkInject::WithoutSpanContext", + "name": "BenchmarkStringSliceValue", + "uri": "attribute/internal/attribute_test.go::BenchmarkStringSliceValue", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -843,5 +776,72 @@ expression: results "stats": "[stats]" } ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkExtract::BogusVersion", + "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::BogusVersion", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkExtract::FutureAdditionalData", + "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::FutureAdditionalData", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkExtract::Sampled", + "uri": "propagation/trace_context_benchmark_test.go::BenchmarkExtract::Sampled", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkInject::SampledSpanContext", + "uri": "propagation/trace_context_benchmark_test.go::BenchmarkInject::SampledSpanContext", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkInject::WithoutSpanContext", + "uri": "propagation/trace_context_benchmark_test.go::BenchmarkInject::WithoutSpanContext", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] } ] diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@quic-go.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@quic-go.snap index f7732028..91e11d28 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@quic-go.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@quic-go.snap @@ -14,74 +14,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkAppend::1-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppend::1-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppend::2-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppend::2-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppend::4-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppend::4-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppend::8-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppend::8-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppendWithLen::1-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::1-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppendWithLen::2-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::2-byte", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkAppendWithLen::4-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::4-byte", + "name": "BenchmarkConnIDManagerInOrder", + "uri": "conn_id_manager_test.go::BenchmarkConnIDManagerInOrder", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -91,8 +25,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendWithLen::8-byte", - "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::8-byte", + "name": "BenchmarkConnIDManagerReordered", + "uri": "conn_id_manager_test.go::BenchmarkConnIDManagerReordered", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -100,10 +34,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkParse::1-byte", - "uri": "quicvarint/varint_test.go::BenchmarkParse::1-byte", + "name": "BenchmarkHandshake", + "uri": "integrationtests/self/benchmark_test.go::BenchmarkHandshake", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -113,8 +59,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParse::2-byte", - "uri": "quicvarint/varint_test.go::BenchmarkParse::2-byte", + "name": "BenchmarkStreamChurn", + "uri": "integrationtests/self/benchmark_test.go::BenchmarkStreamChurn", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -124,8 +70,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParse::4-byte", - "uri": "quicvarint/varint_test.go::BenchmarkParse::4-byte", + "name": "BenchmarkTransfer::500_kb", + "uri": "integrationtests/self/benchmark_test.go::BenchmarkTransfer::500_kb", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -135,8 +81,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParse::8-byte", - "uri": "quicvarint/varint_test.go::BenchmarkParse::8-byte", + "name": "BenchmarkTransfer::51200_kb", + "uri": "integrationtests/self/benchmark_test.go::BenchmarkTransfer::51200_kb", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -144,10 +90,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkReadBytesReader::1-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::1-byte", + "name": "BenchmarkHistoryIsDuplicate", + "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryIsDuplicate", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -157,8 +115,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadBytesReader::2-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::2-byte", + "name": "BenchmarkHistoryReceiveCommonCase", + "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveCommonCase", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -168,8 +126,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadBytesReader::4-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::4-byte", + "name": "BenchmarkHistoryReceiveReversePacketsWithGaps", + "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveReversePacketsWithGaps", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -179,8 +137,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadBytesReader::8-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::8-byte", + "name": "BenchmarkHistoryReceiveSequentialPackets", + "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveSequentialPackets", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -190,8 +148,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadSimpleReader::1-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::1-byte", + "name": "BenchmarkHistoryReceiveSequentialPacketsWithGaps", + "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveSequentialPacketsWithGaps", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -201,8 +159,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadSimpleReader::2-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::2-byte", + "name": "BenchmarkSendAndAcknowledge::ack_every:_10,_in_flight:_100", + "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_10,_in_flight:_100", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -212,8 +170,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadSimpleReader::4-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::4-byte", + "name": "BenchmarkSendAndAcknowledge::ack_every:_100,_in_flight:_1000", + "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_100,_in_flight:_1000", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -223,8 +181,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkReadSimpleReader::8-byte", - "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::8-byte", + "name": "BenchmarkSendAndAcknowledge::ack_every:_2,_in_flight:_0", + "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_2,_in_flight:_0", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -246,19 +204,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkArbitraryHeaderParsing::dest_100_/_src_150", - "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_100_/_src_150", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkArbitraryHeaderParsing::dest_20_/_src_20", - "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_20_/_src_20", + "name": "BenchmarkPacer", + "uri": "internal/congestion/pacer_test.go::BenchmarkPacer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -266,10 +213,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkArbitraryHeaderParsing::dest_8/_src_10", - "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_8/_src_10", + "name": "BenchmarkHKDFExpandLabelOurs::TLS_AES_128_GCM_SHA256", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_AES_128_GCM_SHA256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -279,8 +238,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkComposeVersionNegotiationPacket", - "uri": "internal/wire/version_negotiation_test.go::BenchmarkComposeVersionNegotiationPacket", + "name": "BenchmarkHKDFExpandLabelOurs::TLS_AES_256_GCM_SHA384", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_AES_256_GCM_SHA384", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -290,8 +249,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkIs0RTTPacket", - "uri": "internal/wire/header_test.go::BenchmarkIs0RTTPacket", + "name": "BenchmarkHKDFExpandLabelOurs::TLS_CHACHA20_POLY1305_SHA256", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_CHACHA20_POLY1305_SHA256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -301,8 +260,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseAckFrame", - "uri": "internal/wire/frame_parser_test.go::BenchmarkParseAckFrame", + "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_128_GCM_SHA256", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_128_GCM_SHA256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -312,8 +271,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseDatagramFrame", - "uri": "internal/wire/frame_parser_test.go::BenchmarkParseDatagramFrame", + "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_256_GCM_SHA384", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_256_GCM_SHA384", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -323,8 +282,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseExtendedHeader", - "uri": "internal/wire/extended_header_test.go::BenchmarkParseExtendedHeader", + "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_CHACHA20_POLY1305_SHA256", + "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_CHACHA20_POLY1305_SHA256", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -334,8 +293,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseInitial::with_token", - "uri": "internal/wire/header_test.go::BenchmarkParseInitial::with_token", + "name": "BenchmarkInitialAEAD::opening_100_bytes", + "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::opening_100_bytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -345,8 +304,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseInitial::without_token", - "uri": "internal/wire/header_test.go::BenchmarkParseInitial::without_token", + "name": "BenchmarkInitialAEAD::opening_1200_bytes", + "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::opening_1200_bytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -356,8 +315,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseOtherFrames", - "uri": "internal/wire/frame_parser_test.go::BenchmarkParseOtherFrames", + "name": "BenchmarkInitialAEAD::sealing_100_bytes", + "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::sealing_100_bytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -367,8 +326,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseRetry", - "uri": "internal/wire/header_test.go::BenchmarkParseRetry", + "name": "BenchmarkInitialAEAD::sealing_1200_bytes", + "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::sealing_1200_bytes", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -378,8 +337,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkParseStreamFrame", - "uri": "internal/wire/frame_parser_test.go::BenchmarkParseStreamFrame", + "name": "BenchmarkInitialAEADCreate", + "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEADCreate", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -389,8 +348,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTransportParameters::with_preferred_address", - "uri": "internal/wire/transport_parameter_test.go::BenchmarkTransportParameters::with_preferred_address", + "name": "BenchmarkPacketDecryption", + "uri": "internal/handshake/updatable_aead_test.go::BenchmarkPacketDecryption", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -400,8 +359,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTransportParameters::without_preferred_address", - "uri": "internal/wire/transport_parameter_test.go::BenchmarkTransportParameters::without_preferred_address", + "name": "BenchmarkPacketEncryption", + "uri": "internal/handshake/updatable_aead_test.go::BenchmarkPacketEncryption", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -411,8 +370,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkWriteShortHeader", - "uri": "internal/wire/short_header_test.go::BenchmarkWriteShortHeader", + "name": "BenchmarkRollKeys", + "uri": "internal/handshake/updatable_aead_test.go::BenchmarkRollKeys", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -434,8 +393,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkConnIDManagerInOrder", - "uri": "conn_id_manager_test.go::BenchmarkConnIDManagerInOrder", + "name": "BenchmarkNow::Now", + "uri": "internal/monotime/time_test.go::BenchmarkNow::Now", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -445,8 +404,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkConnIDManagerReordered", - "uri": "conn_id_manager_test.go::BenchmarkConnIDManagerReordered", + "name": "BenchmarkNow::time.Now", + "uri": "internal/monotime/time_test.go::BenchmarkNow::time.Now", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -491,8 +450,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkConnectionTracing", - "uri": "qlog/benchmark_test.go::BenchmarkConnectionTracing", + "name": "BenchmarkRingBuffer", + "uri": "internal/utils/ringbuffer/ringbuffer_bench_test.go::BenchmarkRingBuffer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -514,8 +473,8 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkHKDFExpandLabelOurs::TLS_AES_128_GCM_SHA256", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_AES_128_GCM_SHA256", + "name": "BenchmarkArbitraryHeaderParsing::dest_100_/_src_150", + "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_100_/_src_150", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -525,8 +484,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHKDFExpandLabelOurs::TLS_AES_256_GCM_SHA384", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_AES_256_GCM_SHA384", + "name": "BenchmarkArbitraryHeaderParsing::dest_20_/_src_20", + "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_20_/_src_20", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -536,8 +495,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHKDFExpandLabelOurs::TLS_CHACHA20_POLY1305_SHA256", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelOurs::TLS_CHACHA20_POLY1305_SHA256", + "name": "BenchmarkArbitraryHeaderParsing::dest_8/_src_10", + "uri": "internal/wire/header_test.go::BenchmarkArbitraryHeaderParsing::dest_8/_src_10", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -547,8 +506,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_128_GCM_SHA256", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_128_GCM_SHA256", + "name": "BenchmarkComposeVersionNegotiationPacket", + "uri": "internal/wire/version_negotiation_test.go::BenchmarkComposeVersionNegotiationPacket", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -558,8 +517,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_256_GCM_SHA384", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_AES_256_GCM_SHA384", + "name": "BenchmarkIs0RTTPacket", + "uri": "internal/wire/header_test.go::BenchmarkIs0RTTPacket", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -569,8 +528,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHKDFExpandLabelStandardLibrary::TLS_CHACHA20_POLY1305_SHA256", - "uri": "internal/handshake/hkdf_test.go::BenchmarkHKDFExpandLabelStandardLibrary::TLS_CHACHA20_POLY1305_SHA256", + "name": "BenchmarkParseAckFrame", + "uri": "internal/wire/frame_parser_test.go::BenchmarkParseAckFrame", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -580,8 +539,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInitialAEAD::opening_100_bytes", - "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::opening_100_bytes", + "name": "BenchmarkParseDatagramFrame", + "uri": "internal/wire/frame_parser_test.go::BenchmarkParseDatagramFrame", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -591,8 +550,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInitialAEAD::opening_1200_bytes", - "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::opening_1200_bytes", + "name": "BenchmarkParseExtendedHeader", + "uri": "internal/wire/extended_header_test.go::BenchmarkParseExtendedHeader", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -602,8 +561,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInitialAEAD::sealing_100_bytes", - "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::sealing_100_bytes", + "name": "BenchmarkParseInitial::with_token", + "uri": "internal/wire/header_test.go::BenchmarkParseInitial::with_token", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -613,8 +572,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInitialAEAD::sealing_1200_bytes", - "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEAD::sealing_1200_bytes", + "name": "BenchmarkParseInitial::without_token", + "uri": "internal/wire/header_test.go::BenchmarkParseInitial::without_token", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -624,8 +583,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkInitialAEADCreate", - "uri": "internal/handshake/initial_aead_test.go::BenchmarkInitialAEADCreate", + "name": "BenchmarkParseOtherFrames", + "uri": "internal/wire/frame_parser_test.go::BenchmarkParseOtherFrames", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -635,8 +594,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkPacketDecryption", - "uri": "internal/handshake/updatable_aead_test.go::BenchmarkPacketDecryption", + "name": "BenchmarkParseRetry", + "uri": "internal/wire/header_test.go::BenchmarkParseRetry", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -646,8 +605,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkPacketEncryption", - "uri": "internal/handshake/updatable_aead_test.go::BenchmarkPacketEncryption", + "name": "BenchmarkParseStreamFrame", + "uri": "internal/wire/frame_parser_test.go::BenchmarkParseStreamFrame", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -657,8 +616,30 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkRollKeys", - "uri": "internal/handshake/updatable_aead_test.go::BenchmarkRollKeys", + "name": "BenchmarkTransportParameters::with_preferred_address", + "uri": "internal/wire/transport_parameter_test.go::BenchmarkTransportParameters::with_preferred_address", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkTransportParameters::without_preferred_address", + "uri": "internal/wire/transport_parameter_test.go::BenchmarkTransportParameters::without_preferred_address", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkWriteShortHeader", + "uri": "internal/wire/short_header_test.go::BenchmarkWriteShortHeader", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -680,8 +661,31 @@ expression: results }, "benchmarks": [ { - "name": "BenchmarkHandshake", - "uri": "integrationtests/self/benchmark_test.go::BenchmarkHandshake", + "name": "BenchmarkConnectionTracing", + "uri": "qlog/benchmark_test.go::BenchmarkConnectionTracing", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkAppend::1-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppend::1-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -691,8 +695,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkStreamChurn", - "uri": "integrationtests/self/benchmark_test.go::BenchmarkStreamChurn", + "name": "BenchmarkAppend::2-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppend::2-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -702,8 +706,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTransfer::500_kb", - "uri": "integrationtests/self/benchmark_test.go::BenchmarkTransfer::500_kb", + "name": "BenchmarkAppend::4-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppend::4-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -713,8 +717,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkTransfer::51200_kb", - "uri": "integrationtests/self/benchmark_test.go::BenchmarkTransfer::51200_kb", + "name": "BenchmarkAppend::8-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppend::8-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -722,22 +726,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkHistoryIsDuplicate", - "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryIsDuplicate", + "name": "BenchmarkAppendWithLen::1-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::1-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -747,8 +739,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHistoryReceiveCommonCase", - "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveCommonCase", + "name": "BenchmarkAppendWithLen::2-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::2-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -758,8 +750,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHistoryReceiveReversePacketsWithGaps", - "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveReversePacketsWithGaps", + "name": "BenchmarkAppendWithLen::4-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::4-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -769,8 +761,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHistoryReceiveSequentialPackets", - "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveSequentialPackets", + "name": "BenchmarkAppendWithLen::8-byte", + "uri": "quicvarint/varint_test.go::BenchmarkAppendWithLen::8-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -780,8 +772,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHistoryReceiveSequentialPacketsWithGaps", - "uri": "internal/ackhandler/received_packet_history_test.go::BenchmarkHistoryReceiveSequentialPacketsWithGaps", + "name": "BenchmarkParse::1-byte", + "uri": "quicvarint/varint_test.go::BenchmarkParse::1-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -791,8 +783,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSendAndAcknowledge::ack_every:_10,_in_flight:_100", - "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_10,_in_flight:_100", + "name": "BenchmarkParse::2-byte", + "uri": "quicvarint/varint_test.go::BenchmarkParse::2-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -802,8 +794,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSendAndAcknowledge::ack_every:_100,_in_flight:_1000", - "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_100,_in_flight:_1000", + "name": "BenchmarkParse::4-byte", + "uri": "quicvarint/varint_test.go::BenchmarkParse::4-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -813,8 +805,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSendAndAcknowledge::ack_every:_2,_in_flight:_0", - "uri": "internal/ackhandler/sent_packet_handler_test.go::BenchmarkSendAndAcknowledge::ack_every:_2,_in_flight:_0", + "name": "BenchmarkParse::8-byte", + "uri": "quicvarint/varint_test.go::BenchmarkParse::8-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -822,22 +814,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkNow::Now", - "uri": "internal/monotime/time_test.go::BenchmarkNow::Now", + "name": "BenchmarkReadBytesReader::1-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::1-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -847,8 +827,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkNow::time.Now", - "uri": "internal/monotime/time_test.go::BenchmarkNow::time.Now", + "name": "BenchmarkReadBytesReader::2-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::2-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -856,22 +836,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkPacer", - "uri": "internal/congestion/pacer_test.go::BenchmarkPacer", + "name": "BenchmarkReadBytesReader::4-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::4-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -879,22 +847,54 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkRingBuffer", - "uri": "internal/utils/ringbuffer/ringbuffer_bench_test.go::BenchmarkRingBuffer", + "name": "BenchmarkReadBytesReader::8-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadBytesReader::8-byte", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkReadSimpleReader::1-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::1-byte", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkReadSimpleReader::2-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::2-byte", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkReadSimpleReader::4-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::4-byte", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkReadSimpleReader::8-byte", + "uri": "quicvarint/varint_test.go::BenchmarkReadSimpleReader::8-byte", "config": { "warmup_time_ns": null, "min_round_time_ns": null, diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap index c700368b..cdf3030f 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zap.snap @@ -444,6 +444,74 @@ expression: results } ] }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkBuffers::ByteSlice", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::ByteSlice", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkBuffers::BytesBuffer", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::BytesBuffer", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + }, + { + "name": "BenchmarkBuffers::CustomBuffer", + "uri": "buffer/buffer_test.go::BenchmarkBuffers::CustomBuffer", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ + { + "name": "BenchmarkTake", + "uri": "internal/stacktrace/stack_test.go::BenchmarkTake", + "config": { + "warmup_time_ns": null, + "min_round_time_ns": null, + "max_time_ns": null, + "max_rounds": null + }, + "stats": "[stats]" + } + ] + }, { "creator": { "name": "codspeed-go", @@ -643,74 +711,6 @@ expression: results } ] }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkBuffers::ByteSlice", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::ByteSlice", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkBuffers::BytesBuffer", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::BytesBuffer", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - }, - { - "name": "BenchmarkBuffers::CustomBuffer", - "uri": "buffer/buffer_test.go::BenchmarkBuffers::CustomBuffer", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ - { - "name": "BenchmarkTake", - "uri": "internal/stacktrace/stack_test.go::BenchmarkTake", - "config": { - "warmup_time_ns": null, - "min_round_time_ns": null, - "max_time_ns": null, - "max_rounds": null - }, - "stats": "[stats]" - } - ] - }, { "creator": { "name": "codspeed-go", diff --git a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap index d3c5fc64..19a685b2 100644 --- a/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap +++ b/go-runner/src/snapshots/codspeed_go_runner__integration_tests__assert_results_snapshots@zerolog.snap @@ -14,8 +14,8 @@ expression: results }, "benchmarks": [ { - "name": "Benchmark::Pooler", - "uri": "diode/diode_test.go::Benchmark::Pooler", + "name": "BenchmarkConsoleWriter", + "uri": "console_test.go::BenchmarkConsoleWriter", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -25,8 +25,8 @@ expression: results "stats": "[stats]" }, { - "name": "Benchmark::Waiter", - "uri": "diode/diode_test.go::Benchmark::Waiter", + "name": "BenchmarkContextAppend", + "uri": "benchmark_test.go::BenchmarkContextAppend", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -34,22 +34,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkAppendBytes::EncodingFirst", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingFirst", + "name": "BenchmarkContextFieldType::Bool", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Bool", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -59,8 +47,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::EncodingLast", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingLast", + "name": "BenchmarkContextFieldType::Bools", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Bools", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -70,8 +58,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::EncodingMiddle", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingMiddle", + "name": "BenchmarkContextFieldType::Ctx", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Ctx", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -81,8 +69,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::MultiBytesFirst", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesFirst", + "name": "BenchmarkContextFieldType::Dur", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Dur", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -92,8 +80,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::MultiBytesLast", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesLast", + "name": "BenchmarkContextFieldType::Durs", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Durs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -103,8 +91,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::MultiBytesMiddle", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesMiddle", + "name": "BenchmarkContextFieldType::Err", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Err", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -114,8 +102,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendBytes::NoEncoding", - "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::NoEncoding", + "name": "BenchmarkContextFieldType::Errs", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Errs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -125,8 +113,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingFirst", - "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingFirst", + "name": "BenchmarkContextFieldType::Float", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Float", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -136,8 +124,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingLast", - "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingLast", + "name": "BenchmarkContextFieldType::Floats", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Floats", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -147,8 +135,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingMiddle", - "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingMiddle", + "name": "BenchmarkContextFieldType::Int", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Int", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -158,8 +146,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesFirst", - "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesFirst", + "name": "BenchmarkContextFieldType::Interface", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -169,8 +157,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesLast", - "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesLast", + "name": "BenchmarkContextFieldType::Interface(Object)", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface(Object)", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -180,8 +168,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesMiddle", - "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesMiddle", + "name": "BenchmarkContextFieldType::Interface(Objects)", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface(Objects)", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -191,8 +179,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::NoEncoding", - "uri": "internal/json/string_test.go::BenchmarkAppendString::NoEncoding", + "name": "BenchmarkContextFieldType::Interfaces", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Interfaces", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -202,8 +190,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkEncoder_AppendFloat32", - "uri": "internal/json/types_test.go::BenchmarkEncoder_AppendFloat32", + "name": "BenchmarkContextFieldType::Ints", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Ints", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -213,8 +201,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkEncoder_AppendFloat64", - "uri": "internal/json/types_test.go::BenchmarkEncoder_AppendFloat64", + "name": "BenchmarkContextFieldType::Object", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Object", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -222,22 +210,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkAppendFloat::Float32", - "uri": "internal/cbor/types_test.go::BenchmarkAppendFloat::Float32", + "name": "BenchmarkContextFieldType::Str", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Str", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -247,8 +223,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendFloat::Float64", - "uri": "internal/cbor/types_test.go::BenchmarkAppendFloat::Float64", + "name": "BenchmarkContextFieldType::Stringer", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Stringer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -258,8 +234,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int-Negative", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int-Negative", + "name": "BenchmarkContextFieldType::Strs", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Strs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -269,8 +245,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int-Positive", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int-Positive", + "name": "BenchmarkContextFieldType::Time", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Time", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -280,8 +256,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int16", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int16", + "name": "BenchmarkContextFieldType::Times", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Times", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -291,8 +267,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int32", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int32", + "name": "BenchmarkContextFieldType::Timestamp", + "uri": "benchmark_test.go::BenchmarkContextFieldType::Timestamp", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -302,8 +278,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int64", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int64", + "name": "BenchmarkContextFields", + "uri": "benchmark_test.go::BenchmarkContextFields", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -313,8 +289,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::int8", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int8", + "name": "BenchmarkDisabled", + "uri": "benchmark_test.go::BenchmarkDisabled", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -324,8 +300,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::uint16", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint16", + "name": "BenchmarkHooks::Nop/Multi", + "uri": "hook_test.go::BenchmarkHooks::Nop/Multi", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -335,8 +311,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::uint32", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint32", + "name": "BenchmarkHooks::Nop/Single", + "uri": "hook_test.go::BenchmarkHooks::Nop/Single", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -346,8 +322,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::uint64", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint64", + "name": "BenchmarkHooks::Simple", + "uri": "hook_test.go::BenchmarkHooks::Simple", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -357,8 +333,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendInt::uint8", - "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint8", + "name": "BenchmarkInfo", + "uri": "benchmark_test.go::BenchmarkInfo", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -368,8 +344,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingFirst", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingFirst", + "name": "BenchmarkLogArrayObject", + "uri": "benchmark_test.go::BenchmarkLogArrayObject", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -379,8 +355,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingLast", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingLast", + "name": "BenchmarkLogEmpty", + "uri": "benchmark_test.go::BenchmarkLogEmpty", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -390,8 +366,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::EncodingMiddle", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingMiddle", + "name": "BenchmarkLogFieldType::Bool", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Bool", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -401,8 +377,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesFirst", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesFirst", + "name": "BenchmarkLogFieldType::Bools", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Bools", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -412,8 +388,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesLast", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesLast", + "name": "BenchmarkLogFieldType::Ctx", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Ctx", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -423,8 +399,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::MultiBytesMiddle", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesMiddle", + "name": "BenchmarkLogFieldType::Dur", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Dur", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -434,8 +410,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendString::NoEncoding", - "uri": "internal/cbor/string_test.go::BenchmarkAppendString::NoEncoding", + "name": "BenchmarkLogFieldType::Durs", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Durs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -445,8 +421,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendTime::Float", - "uri": "internal/cbor/time_test.go::BenchmarkAppendTime::Float", + "name": "BenchmarkLogFieldType::Err", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Err", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -456,8 +432,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkAppendTime::Integer", - "uri": "internal/cbor/time_test.go::BenchmarkAppendTime::Integer", + "name": "BenchmarkLogFieldType::Errs", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Errs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -465,22 +441,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkConsoleWriter", - "uri": "console_test.go::BenchmarkConsoleWriter", + "name": "BenchmarkLogFieldType::Float", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Float", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -490,8 +454,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextAppend", - "uri": "benchmark_test.go::BenchmarkContextAppend", + "name": "BenchmarkLogFieldType::Floats", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Floats", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -501,8 +465,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Bool", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Bool", + "name": "BenchmarkLogFieldType::Int", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Int", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -512,8 +476,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Bools", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Bools", + "name": "BenchmarkLogFieldType::Interface", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -523,8 +487,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Ctx", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Ctx", + "name": "BenchmarkLogFieldType::Interface(Object)", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface(Object)", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -534,8 +498,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Dur", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Dur", + "name": "BenchmarkLogFieldType::Interface(Objects)", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface(Objects)", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -545,8 +509,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Durs", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Durs", + "name": "BenchmarkLogFieldType::Interfaces", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Interfaces", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -556,8 +520,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Err", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Err", + "name": "BenchmarkLogFieldType::Ints", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Ints", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -567,8 +531,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Errs", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Errs", + "name": "BenchmarkLogFieldType::Object", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Object", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -578,8 +542,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Float", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Float", + "name": "BenchmarkLogFieldType::Str", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Str", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -589,8 +553,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Floats", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Floats", + "name": "BenchmarkLogFieldType::Strs", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Strs", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -600,8 +564,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Int", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Int", + "name": "BenchmarkLogFieldType::Time", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Time", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -611,8 +575,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Interface", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface", + "name": "BenchmarkLogFieldType::Times", + "uri": "benchmark_test.go::BenchmarkLogFieldType::Times", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -622,8 +586,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Interface(Object)", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface(Object)", + "name": "BenchmarkLogFields", + "uri": "benchmark_test.go::BenchmarkLogFields", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -633,8 +597,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Interface(Objects)", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Interface(Objects)", + "name": "BenchmarkSamplers::BasicSampler_0", + "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_0", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -644,8 +608,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Interfaces", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Interfaces", + "name": "BenchmarkSamplers::BasicSampler_1", + "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_1", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -655,8 +619,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Ints", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Ints", + "name": "BenchmarkSamplers::BasicSampler_5", + "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_5", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -666,8 +630,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Object", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Object", + "name": "BenchmarkSamplers::BurstSampler", + "uri": "sampler_test.go::BenchmarkSamplers::BurstSampler", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -677,8 +641,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Str", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Str", + "name": "BenchmarkSamplers::BurstSamplerNext", + "uri": "sampler_test.go::BenchmarkSamplers::BurstSamplerNext", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -688,8 +652,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Stringer", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Stringer", + "name": "BenchmarkSamplers::BurstSampler_0", + "uri": "sampler_test.go::BenchmarkSamplers::BurstSampler_0", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -699,8 +663,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Strs", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Strs", + "name": "BenchmarkSamplers::RandomSampler", + "uri": "sampler_test.go::BenchmarkSamplers::RandomSampler", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -710,8 +674,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Time", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Time", + "name": "BenchmarkSamplers::RandomSampler_0", + "uri": "sampler_test.go::BenchmarkSamplers::RandomSampler_0", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -719,10 +683,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkContextFieldType::Times", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Times", + "name": "Benchmark::Pooler", + "uri": "diode/diode_test.go::Benchmark::Pooler", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -732,8 +708,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkContextFieldType::Timestamp", - "uri": "benchmark_test.go::BenchmarkContextFieldType::Timestamp", + "name": "Benchmark::Waiter", + "uri": "diode/diode_test.go::Benchmark::Waiter", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -741,10 +717,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkContextFields", - "uri": "benchmark_test.go::BenchmarkContextFields", + "name": "BenchmarkDataRace", + "uri": "hlog/hlog_test.go::BenchmarkDataRace", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -754,8 +742,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkDisabled", - "uri": "benchmark_test.go::BenchmarkDisabled", + "name": "BenchmarkHandlers::Combined", + "uri": "hlog/hlog_test.go::BenchmarkHandlers::Combined", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -765,8 +753,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHooks::Nop/Multi", - "uri": "hook_test.go::BenchmarkHooks::Nop/Multi", + "name": "BenchmarkHandlers::CombinedDisabled", + "uri": "hlog/hlog_test.go::BenchmarkHandlers::CombinedDisabled", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -776,8 +764,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHooks::Nop/Single", - "uri": "hook_test.go::BenchmarkHooks::Nop/Single", + "name": "BenchmarkHandlers::Single", + "uri": "hlog/hlog_test.go::BenchmarkHandlers::Single", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -787,8 +775,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHooks::Simple", - "uri": "hook_test.go::BenchmarkHooks::Simple", + "name": "BenchmarkHandlers::SingleDisabled", + "uri": "hlog/hlog_test.go::BenchmarkHandlers::SingleDisabled", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -796,10 +784,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkInfo", - "uri": "benchmark_test.go::BenchmarkInfo", + "name": "BenchmarkAppendFloat::Float32", + "uri": "internal/cbor/types_test.go::BenchmarkAppendFloat::Float32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -809,8 +809,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogArrayObject", - "uri": "benchmark_test.go::BenchmarkLogArrayObject", + "name": "BenchmarkAppendFloat::Float64", + "uri": "internal/cbor/types_test.go::BenchmarkAppendFloat::Float64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -820,8 +820,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogEmpty", - "uri": "benchmark_test.go::BenchmarkLogEmpty", + "name": "BenchmarkAppendInt::int-Negative", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int-Negative", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -831,8 +831,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Bool", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Bool", + "name": "BenchmarkAppendInt::int-Positive", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int-Positive", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -842,8 +842,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Bools", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Bools", + "name": "BenchmarkAppendInt::int16", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int16", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -853,8 +853,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Ctx", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Ctx", + "name": "BenchmarkAppendInt::int32", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -864,8 +864,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Dur", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Dur", + "name": "BenchmarkAppendInt::int64", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -875,8 +875,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Durs", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Durs", + "name": "BenchmarkAppendInt::int8", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::int8", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -886,8 +886,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Err", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Err", + "name": "BenchmarkAppendInt::uint16", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint16", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -897,8 +897,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Errs", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Errs", + "name": "BenchmarkAppendInt::uint32", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -908,8 +908,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Float", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Float", + "name": "BenchmarkAppendInt::uint64", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -919,8 +919,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Floats", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Floats", + "name": "BenchmarkAppendInt::uint8", + "uri": "internal/cbor/types_test.go::BenchmarkAppendInt::uint8", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -930,8 +930,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Int", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Int", + "name": "BenchmarkAppendString::EncodingFirst", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -941,8 +941,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Interface", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface", + "name": "BenchmarkAppendString::EncodingLast", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -952,8 +952,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Interface(Object)", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface(Object)", + "name": "BenchmarkAppendString::EncodingMiddle", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::EncodingMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -963,8 +963,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Interface(Objects)", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Interface(Objects)", + "name": "BenchmarkAppendString::MultiBytesFirst", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -974,8 +974,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Interfaces", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Interfaces", + "name": "BenchmarkAppendString::MultiBytesLast", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -985,8 +985,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Ints", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Ints", + "name": "BenchmarkAppendString::MultiBytesMiddle", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::MultiBytesMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -996,8 +996,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Object", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Object", + "name": "BenchmarkAppendString::NoEncoding", + "uri": "internal/cbor/string_test.go::BenchmarkAppendString::NoEncoding", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1007,8 +1007,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Str", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Str", + "name": "BenchmarkAppendTime::Float", + "uri": "internal/cbor/time_test.go::BenchmarkAppendTime::Float", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1018,8 +1018,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Strs", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Strs", + "name": "BenchmarkAppendTime::Integer", + "uri": "internal/cbor/time_test.go::BenchmarkAppendTime::Integer", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1027,10 +1027,22 @@ expression: results "max_rounds": null }, "stats": "[stats]" - }, + } + ] + }, + { + "creator": { + "name": "codspeed-go", + "version": "[version]", + "pid": "[pid]" + }, + "instrument": { + "type": "walltime" + }, + "benchmarks": [ { - "name": "BenchmarkLogFieldType::Time", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Time", + "name": "BenchmarkAppendBytes::EncodingFirst", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1040,8 +1052,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFieldType::Times", - "uri": "benchmark_test.go::BenchmarkLogFieldType::Times", + "name": "BenchmarkAppendBytes::EncodingLast", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1051,8 +1063,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkLogFields", - "uri": "benchmark_test.go::BenchmarkLogFields", + "name": "BenchmarkAppendBytes::EncodingMiddle", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::EncodingMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1062,8 +1074,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BasicSampler_0", - "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_0", + "name": "BenchmarkAppendBytes::MultiBytesFirst", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1073,8 +1085,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BasicSampler_1", - "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_1", + "name": "BenchmarkAppendBytes::MultiBytesLast", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1084,8 +1096,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BasicSampler_5", - "uri": "sampler_test.go::BenchmarkSamplers::BasicSampler_5", + "name": "BenchmarkAppendBytes::MultiBytesMiddle", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::MultiBytesMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1095,8 +1107,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BurstSampler", - "uri": "sampler_test.go::BenchmarkSamplers::BurstSampler", + "name": "BenchmarkAppendBytes::NoEncoding", + "uri": "internal/json/bytes_test.go::BenchmarkAppendBytes::NoEncoding", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1106,8 +1118,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BurstSamplerNext", - "uri": "sampler_test.go::BenchmarkSamplers::BurstSamplerNext", + "name": "BenchmarkAppendString::EncodingFirst", + "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1117,8 +1129,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::BurstSampler_0", - "uri": "sampler_test.go::BenchmarkSamplers::BurstSampler_0", + "name": "BenchmarkAppendString::EncodingLast", + "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1128,8 +1140,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::RandomSampler", - "uri": "sampler_test.go::BenchmarkSamplers::RandomSampler", + "name": "BenchmarkAppendString::EncodingMiddle", + "uri": "internal/json/string_test.go::BenchmarkAppendString::EncodingMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1139,8 +1151,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkSamplers::RandomSampler_0", - "uri": "sampler_test.go::BenchmarkSamplers::RandomSampler_0", + "name": "BenchmarkAppendString::MultiBytesFirst", + "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesFirst", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1148,22 +1160,10 @@ expression: results "max_rounds": null }, "stats": "[stats]" - } - ] - }, - { - "creator": { - "name": "codspeed-go", - "version": "[version]", - "pid": "[pid]" - }, - "instrument": { - "type": "walltime" - }, - "benchmarks": [ + }, { - "name": "BenchmarkDataRace", - "uri": "hlog/hlog_test.go::BenchmarkDataRace", + "name": "BenchmarkAppendString::MultiBytesLast", + "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesLast", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1173,8 +1173,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHandlers::Combined", - "uri": "hlog/hlog_test.go::BenchmarkHandlers::Combined", + "name": "BenchmarkAppendString::MultiBytesMiddle", + "uri": "internal/json/string_test.go::BenchmarkAppendString::MultiBytesMiddle", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1184,8 +1184,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHandlers::CombinedDisabled", - "uri": "hlog/hlog_test.go::BenchmarkHandlers::CombinedDisabled", + "name": "BenchmarkAppendString::NoEncoding", + "uri": "internal/json/string_test.go::BenchmarkAppendString::NoEncoding", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1195,8 +1195,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHandlers::Single", - "uri": "hlog/hlog_test.go::BenchmarkHandlers::Single", + "name": "BenchmarkEncoder_AppendFloat32", + "uri": "internal/json/types_test.go::BenchmarkEncoder_AppendFloat32", "config": { "warmup_time_ns": null, "min_round_time_ns": null, @@ -1206,8 +1206,8 @@ expression: results "stats": "[stats]" }, { - "name": "BenchmarkHandlers::SingleDisabled", - "uri": "hlog/hlog_test.go::BenchmarkHandlers::SingleDisabled", + "name": "BenchmarkEncoder_AppendFloat64", + "uri": "internal/json/types_test.go::BenchmarkEncoder_AppendFloat64", "config": { "warmup_time_ns": null, "min_round_time_ns": null, From 7065daf4c912617a3ba7f0129011500817f9ccdb Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 12:26:33 +0100 Subject: [PATCH 10/13] fix(go-runner): add support for go1.24 --- Cargo.lock | 1 + go-runner/Cargo.toml | 1 + go-runner/overlay/README.md | 30 + go-runner/overlay/benchmark1.24.0.go | 1093 +++++++++++++++++ go-runner/overlay/benchmark1.24.0.patch | 354 ++++++ .../{benchmark.go => benchmark1.25.0.go} | 87 -- go-runner/overlay/benchmark1.25.0.patch | 298 +++++ go-runner/overlay/codspeed.go | 87 ++ go-runner/src/runner/overlay/mod.rs | 30 +- 9 files changed, 1890 insertions(+), 91 deletions(-) create mode 100644 go-runner/overlay/README.md create mode 100644 go-runner/overlay/benchmark1.24.0.go create mode 100644 go-runner/overlay/benchmark1.24.0.patch rename go-runner/overlay/{benchmark.go => benchmark1.25.0.go} (92%) create mode 100644 go-runner/overlay/benchmark1.25.0.patch diff --git a/Cargo.lock b/Cargo.lock index f7690ea5..0e9ac616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -293,6 +293,7 @@ dependencies = [ "regex", "reqwest", "rstest", + "semver", "serde", "serde_json", "statrs", diff --git a/go-runner/Cargo.toml b/go-runner/Cargo.toml index 415a985e..b9bfb27a 100644 --- a/go-runner/Cargo.toml +++ b/go-runner/Cargo.toml @@ -22,6 +22,7 @@ tar = "0.4.44" reqwest = { version = "0.13.1", features = ["blocking"] } rayon = "1.11.0" itertools = "0.14.0" +semver = "1.0" [dev-dependencies] divan = { version = "4.1.0", package = "codspeed-divan-compat" } diff --git a/go-runner/overlay/README.md b/go-runner/overlay/README.md new file mode 100644 index 00000000..9fc38cc9 --- /dev/null +++ b/go-runner/overlay/README.md @@ -0,0 +1,30 @@ +# Go Benchmark Overlay Patches + +This directory contains CodSpeed instrumentation overlays for Go's standard `testing` package benchmarks. + +## Files + +- `benchmark1.24.0.go`, `benchmark1.25.0.go` - Modified versions of Go's `testing/benchmark.go` with CodSpeed instrumentation +- `benchmark1.24.0.patch`, `benchmark1.25.0.patch` - Patch files showing differences from upstream +- `codspeed.go` - CodSpeed-specific benchmark extensions +- `instrument-hooks.go` - Bindings to the instrument-hooks library + +## Supporting a new Go Version + +To generate the patch files, run this (or use the existing patches): +```bash +# Download the unpatched file: +export VERSION=1.25.0 +wget -O benchmark$VERSION.go https://github.com/golang/go/raw/refs/tags/go$VERSION/src/testing/benchmark.go + +# Then compare against the patched file (same version!): +diff -a -u -N benchmark$VERSION.go overlay/benchmark$VERSION.go > overlay/benchmark$VERSION.patch +``` + +You can then download the latest benchmark file and apply the patch: +```bash +wget -O overlay/benchmark$VERSION.go https://github.com/golang/go/raw/refs/tags/go$VERSION/src/testing/benchmark.go +patch overlay/benchmark$VERSION.go < overlay/benchmark$VERSION.patch +``` + +Then manually fix any conflicts or issues that arise. diff --git a/go-runner/overlay/benchmark1.24.0.go b/go-runner/overlay/benchmark1.24.0.go new file mode 100644 index 00000000..fd4c0fa1 --- /dev/null +++ b/go-runner/overlay/benchmark1.24.0.go @@ -0,0 +1,1093 @@ +// Copyright 2009 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 + +import ( + "context" + "flag" + "fmt" + "internal/sysinfo" + "io" + "math" + "os" + "runtime" + "slices" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + "unicode" +) + +func initBenchmarkFlags() { + matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`") + benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks") + flag.Var(&benchTime, "test.benchtime", "run each benchmark for duration `d` or N times if `d` is of the form Nx") +} + +var ( + matchBenchmarks *string + benchmarkMemory *bool + + benchTime = durationOrCountFlag{d: 1 * time.Second} // changed during test of testing package +) + +type durationOrCountFlag struct { + d time.Duration + n int + allowZero bool +} + +func (f *durationOrCountFlag) String() string { + if f.n > 0 { + return fmt.Sprintf("%dx", f.n) + } + return f.d.String() +} + +func (f *durationOrCountFlag) Set(s string) error { + if strings.HasSuffix(s, "x") { + n, err := strconv.ParseInt(s[:len(s)-1], 10, 0) + if err != nil || n < 0 || (!f.allowZero && n == 0) { + return fmt.Errorf("invalid count") + } + *f = durationOrCountFlag{n: int(n)} + return nil + } + d, err := time.ParseDuration(s) + if err != nil || d < 0 || (!f.allowZero && d == 0) { + return fmt.Errorf("invalid duration") + } + *f = durationOrCountFlag{d: d} + return nil +} + +// Global lock to ensure only one benchmark runs at a time. +var benchmarkLock sync.Mutex + +// Used for every benchmark for measuring memory. +var memStats runtime.MemStats + +// InternalBenchmark is an internal type but exported because it is cross-package; +// it is part of the implementation of the "go test" command. +type InternalBenchmark struct { + Name string + F func(b *B) +} + +// B is a type passed to [Benchmark] functions to manage benchmark +// timing and control the number of iterations. +// +// A benchmark ends when its Benchmark function returns or calls any of the methods +// FailNow, Fatal, Fatalf, SkipNow, Skip, or Skipf. Those methods must be called +// only from the goroutine running the Benchmark function. +// The other reporting methods, such as the variations of Log and Error, +// may be called simultaneously from multiple goroutines. +// +// Like in tests, benchmark logs are accumulated during execution +// and dumped to standard output when done. Unlike in tests, benchmark logs +// are always printed, so as not to hide output whose existence may be +// affecting benchmark results. +type B struct { + common + codspeed + importPath string // import path of the package containing the benchmark + bstate *benchState + N int + previousN int // number of iterations in the previous run + previousDuration time.Duration // total duration of the previous run + benchFunc func(b *B) + benchTime durationOrCountFlag + bytes int64 + missingBytes bool // one of the subbenchmarks does not have bytes set. + timerOn bool + showAllocResult bool + result BenchmarkResult + parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines + // The initial states of memStats.Mallocs and memStats.TotalAlloc. + startAllocs uint64 + startBytes uint64 + // The net total of this test after being run. + netAllocs uint64 + netBytes uint64 + // Extra metrics collected by ReportMetric. + extra map[string]float64 + + // loop tracks the state of B.Loop + loop struct { + // n is the target number of iterations. It gets bumped up as we go. + // When the benchmark loop is done, we commit this to b.N so users can + // do reporting based on it, but we avoid exposing it until then. + n uint64 + // i is the current Loop iteration. It's strictly monotonically + // increasing toward n. + // + // The high bit is used to poison the Loop fast path and fall back to + // the slow path. + i uint64 + + done bool // set when B.Loop return false + } +} + +func (b *B) StartTimer() { + timerOn := b.timerOn + + b.StartTimerWithoutMarker() + + if !timerOn { + b.startTimestamp = CurrentTimestamp() + } +} + +func (b *B) StopTimer() { + endTimestamp := CurrentTimestamp() + timerOn := b.timerOn + + b.StopTimerWithoutMarker() + + if timerOn { + b.AddBenchmarkMarkers(endTimestamp) + } +} + +// ResetTimer zeroes the elapsed benchmark time and memory allocation counters +// and deletes user-reported metrics. +// It does not affect whether the timer is running. +func (b *B) ResetTimer() { + if b.extra == nil { + // Allocate the extra map before reading memory stats. + // Pre-size it to make more allocation unlikely. + b.extra = make(map[string]float64, 16) + } else { + clear(b.extra) + } + if b.timerOn { + runtime.ReadMemStats(&memStats) + b.startAllocs = memStats.Mallocs + b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() + + b.startTimestamp = CurrentTimestamp() + } + b.duration = 0 + b.netAllocs = 0 + b.netBytes = 0 + + // Clear CodSpeed timestamp data + b.codspeedItersPerRound = b.codspeedItersPerRound[:0] + b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] + b.startTimestamps = b.startTimestamps[:0] + b.stopTimestamps = b.stopTimestamps[:0] +} + +// SetBytes records the number of bytes processed in a single operation. +// If this is called, the benchmark will report ns/op and MB/s. +func (b *B) SetBytes(n int64) { b.bytes = n } + +// ReportAllocs enables malloc statistics for this benchmark. +// It is equivalent to setting -test.benchmem, but it only affects the +// benchmark function that calls ReportAllocs. +func (b *B) ReportAllocs() { + b.showAllocResult = true +} + +// runN runs a single benchmark for the specified number of iterations. +func (b *B) runN(n int) { + b.__codspeed_root_frame__runN(n) +} + +//go:noinline +func (b *B) __codspeed_root_frame__runN(n int) { + benchmarkLock.Lock() + defer benchmarkLock.Unlock() + ctx, cancelCtx := context.WithCancel(context.Background()) + defer func() { + b.runCleanup(normalPanic) + b.checkRaces() + }() + // Try to get a comparable environment for each run + // by clearing garbage from previous runs. + runtime.GC() + b.resetRaces() + b.N = n + b.loop.n = 0 + b.loop.i = 0 + b.loop.done = false + b.ctx = ctx + b.cancelCtx = cancelCtx + + b.parallelism = 1 + b.ResetTimer() + b.StartTimer() + b.benchFunc(b) + b.StopTimer() + b.SaveMeasurement() + b.previousN = n + b.previousDuration = b.duration + + if b.loop.n > 0 && !b.loop.done && !b.failed { + b.Error("benchmark function returned without B.Loop() == false (break or return in loop?)") + } +} + +// run1 runs the first iteration of benchFunc. It reports whether more +// iterations of this benchmarks should be run. +func (b *B) run1() bool { + if bstate := b.bstate; bstate != nil { + // Extend maxLen, if needed. + if n := len(b.name) + bstate.extLen + 1; n > bstate.maxLen { + bstate.maxLen = n + 8 // Add additional slack to avoid too many jumps in size. + } + } + go func() { + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- true + }() + + b.runN(1) + }() + <-b.signal + if b.failed { + // This case can happen with a `b.Loop()` benchmark if any of the iterations fail + ensureBenchmarkIsStopped(b) + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) + return false + } + // Only print the output if we know we are not going to proceed. + // Otherwise it is printed in processBench. + b.mu.RLock() + finished := b.finished + b.mu.RUnlock() + if b.hasSub.Load() || finished { + tag := "BENCH" + if b.skipped { + tag = "SKIP" + } + if b.chatty != nil && (len(b.output) > 0 || finished) { + b.trimOutput() + fmt.Fprintf(b.w, "%s--- %s: %s\n%s", b.chatty.prefix(), tag, b.name, b.output) + } + return false + } + return true +} + +var labelsOnce sync.Once + +// run executes the benchmark in a separate goroutine, including all of its +// subbenchmarks. b must not have subbenchmarks. +func (b *B) run() { + labelsOnce.Do(func() { + fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") + + fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) + fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { + fmt.Fprintf(b.w, "pkg: %s\n", b.importPath) + } + if cpu := sysinfo.CPUName(); cpu != "" { + fmt.Fprintf(b.w, "cpu: %s\n", cpu) + } + }) + if b.bstate != nil { + // Running go test --test.bench + b.bstate.processBench(b) // Must call doBench. + } else { + // Running func Benchmark. + b.doBench() + } +} + +func (b *B) doBench() BenchmarkResult { + go b.launch() + <-b.signal + return b.result +} + +func predictN(goalns int64, prevIters int64, prevns int64, last int64) int { + if prevns == 0 { + // Round up to dodge divide by zero. See https://go.dev/issue/70709. + prevns = 1 + } + + // Order of operations matters. + // For very fast benchmarks, prevIters ~= prevns. + // If you divide first, you get 0 or 1, + // which can hide an order of magnitude in execution time. + // So multiply first, then divide. + n := goalns * prevIters / prevns + // Run more iterations than we think we'll need (1.2x). + n += n / 5 + // Don't grow too fast in case we had timing errors previously. + n = min(n, 100*last) + // Be sure to run at least one more than last time. + n = max(n, last+1) + // Don't run more than 1e9 times. (This also keeps n in int range on 32 bit platforms.) + n = min(n, 1e9) + return int(n) +} + +// launch launches the benchmark function. It gradually increases the number +// of benchmark iterations until the benchmark runs for the requested benchtime. +// launch is run by the doBench function as a separate goroutine. +// run1 must have been called on b. +func (b *B) launch() { + // Signal that we're done whether we return normally + // or by FailNow's runtime.Goexit. + defer func() { + b.signal <- true + }() + + // b.Loop does its own ramp-up logic so we just need to run it once. + // If b.loop.n is non zero, it means b.Loop has already run. + if b.loop.n == 0 { + // Run the benchmark for at least the specified amount of time. + if b.benchTime.n > 0 { + // We already ran a single iteration in run1. + // If -benchtime=1x was requested, use that result. + // See https://golang.org/issue/32051. + if b.benchTime.n > 1 { + b.runN(b.benchTime.n) + } + } else { + warmupD := b.benchTime.d / 10 + warmupN := int64(1) + for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { + last := n + // Predict required iterations. + goalns := warmupD.Nanoseconds() + prevIters := int64(b.N) + n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) + b.runN(int(n)) + warmupN = n + } + + // Reset the fields from the warmup run + b.ResetTimer() + + // Final run: + benchD := b.benchTime.d + benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) + + // When we have a very slow benchmark (e.g. taking 500ms), we have to: + // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) + // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds + const minRounds = 100 + var rounds int + var roundN int + if benchN < minRounds { + rounds = benchN + roundN = 1 + } else { + rounds = minRounds + roundN = benchN / int(rounds) + } + + b.codspeed.instrument_hooks.StartBenchmark() + for range rounds { + b.runN(int(roundN)) + } + b.codspeed.instrument_hooks.StopBenchmark() + b.sendAccumulatedTimestamps() + } + } + b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} +} + +// Elapsed returns the measured elapsed time of the benchmark. +// The duration reported by Elapsed matches the one measured by +// [B.StartTimer], [B.StopTimer], and [B.ResetTimer]. +func (b *B) Elapsed() time.Duration { + d := b.duration + if b.timerOn { + d += highPrecisionTimeSince(b.start) + } + return d +} + +// ReportMetric adds "n unit" to the reported benchmark results. +// If the metric is per-iteration, the caller should divide by b.N, +// and by convention units should end in "/op". +// ReportMetric overrides any previously reported value for the same unit. +// ReportMetric panics if unit is the empty string or if unit contains +// any whitespace. +// If unit is a unit normally reported by the benchmark framework itself +// (such as "allocs/op"), ReportMetric will override that metric. +// Setting "ns/op" to 0 will suppress that built-in metric. +func (b *B) ReportMetric(n float64, unit string) { + if unit == "" { + panic("metric unit must not be empty") + } + if strings.IndexFunc(unit, unicode.IsSpace) >= 0 { + panic("metric unit must not contain whitespace") + } + b.extra[unit] = n +} + +func (b *B) stopOrScaleBLoop() bool { + t := b.Elapsed() + if t >= b.benchTime.d { + // We've reached the target + return false + } + // Loop scaling + goalns := b.benchTime.d.Nanoseconds() + prevIters := int64(b.loop.n) + b.loop.n = uint64(predictN(goalns, prevIters, t.Nanoseconds(), prevIters)) + if b.loop.n&loopPoisonMask != 0 { + // The iteration count should never get this high, but if it did we'd be + // in big trouble. + panic("loop iteration target overflow") + } + return true +} + +func (b *B) loopSlowPath() bool { + // Consistency checks + // if !b.timerOn { + // b.Fatal("B.Loop called with timer stopped") + // } + if b.loop.i&loopPoisonMask != 0 { + panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) + } + + if b.loop.n == 0 { + // It's the first call to b.Loop() in the benchmark function. + if b.benchTime.n > 0 { + // Fixed iteration count. + b.loop.n = uint64(b.benchTime.n) + } else { + // Initialize target to 1 to kick start loop scaling. + b.loop.n = 1 + } + // Within a b.Loop loop, we don't use b.N (to avoid confusion). + b.N = 0 + b.codspeed.instrument_hooks.StartBenchmark() + b.ResetTimer() + b.StartTimerWithoutMarker() + + // Start the next iteration. + b.loop.i++ + return true + } + + // Should we keep iterating? + var more bool + if b.benchTime.n > 0 { + // The iteration count is fixed, so we should have run this many and now + // be done. + if b.loop.i != uint64(b.benchTime.n) { + // We shouldn't be able to reach the slow path in this case. + panic(fmt.Sprintf("iteration count %d < fixed target %d", b.loop.i, b.benchTime.n)) + } + more = false + } else { + // Handle fixed time case + more = b.stopOrScaleBLoop() + } + if !more { + // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function + // but this will result in a huge performance degradation since the C FFI calls are expensive. + // + // The only downside of having this here, is that there's a small chance of perf sampling the + // benchmark framework code which already happens anyway because we only emit 1 pair of + // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. + endTimestamp := CurrentTimestamp() + + // Edge case: The timer is stopped in b.Loop() which prevents any further calls to + // StopTimer() from adding the benchmark markers. We have to manually submit them here, + // once the benchmark loop is done. + b.AddBenchmarkMarkers(endTimestamp) + b.codspeed.instrument_hooks.StopBenchmark() + b.sendAccumulatedTimestamps() + + // Commit iteration count + b.N = int(b.loop.n) + b.loop.done = true + return false + } + + b.StartTimerWithoutMarker() + // Start the next iteration. + b.loop.i++ + return true +} + +// Loop returns true as long as the benchmark should continue running. +// +// A typical benchmark is structured like: +// +// func Benchmark(b *testing.B) { +// ... setup ... +// for b.Loop() { +// ... code to measure ... +// } +// ... cleanup ... +// } +// +// Loop resets the benchmark timer the first time it is called in a benchmark, +// so any setup performed prior to starting the benchmark loop does not count +// toward the benchmark measurement. Likewise, when it returns false, it stops +// the timer so cleanup code is not measured. +// +// The compiler never optimizes away calls to functions within the body of a +// "for b.Loop() { ... }" loop. This prevents surprises that can otherwise occur +// if the compiler determines that the result of a benchmarked function is +// unused. The loop must be written in exactly this form, and this only applies +// to calls syntactically between the curly braces of the loop. Optimizations +// are performed as usual in any functions called by the loop. +// +// After Loop returns false, b.N contains the total number of iterations that +// ran, so the benchmark may use b.N to compute other average metrics. +// +// Prior to the introduction of Loop, benchmarks were expected to contain an +// explicit loop from 0 to b.N. Benchmarks should either use Loop or contain a +// loop to b.N, but not both. Loop offers more automatic management of the +// benchmark timer, and runs each benchmark function only once per measurement, +// whereas b.N-based benchmarks must run the benchmark function (and any +// associated setup and cleanup) several times. +func (b *B) Loop() bool { + b.StopTimerWithoutMarker() + b.SaveMeasurement() + // This is written such that the fast path is as fast as possible and can be + // inlined. + // + // There are three cases where we'll fall out of the fast path: + // + // - On the first call, both i and n are 0. + // + // - If the loop reaches the n'th iteration, then i == n and we need + // to figure out the new target iteration count or if we're done. + // + // - If the timer is stopped, it poisons the top bit of i so the slow + // path can do consistency checks and fail. + if b.loop.i < b.loop.n { + b.loop.i++ + b.StartTimerWithoutMarker() + return true + } + return b.loopSlowPath() +} + +// The loopPoison constants can be OR'd into B.loop.i to cause it to fall back +// to the slow path. +const ( + loopPoisonTimer = uint64(1 << (63 - iota)) + // If necessary, add more poison bits here. + + // loopPoisonMask is the set of all loop poison bits. (iota-1) is the index + // of the bit we just set, from which we recreate that bit mask. We subtract + // 1 to set all of the bits below that bit, then complement the result to + // get the mask. Sorry, not sorry. + loopPoisonMask = ^uint64((1 << (63 - (iota - 1))) - 1) +) + +// BenchmarkResult contains the results of a benchmark run. +type BenchmarkResult struct { + N int // The number of iterations. + T time.Duration // The total time taken. + Bytes int64 // Bytes processed in one iteration. + MemAllocs uint64 // The total number of memory allocations. + MemBytes uint64 // The total number of bytes allocated. + + CodspeedTimePerRoundNs []time.Duration + CodspeedItersPerRound []int64 + + // Extra records additional metrics reported by ReportMetric. + Extra map[string]float64 +} + +// NsPerOp returns the "ns/op" metric. +func (r BenchmarkResult) NsPerOp() int64 { + if v, ok := r.Extra["ns/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return r.T.Nanoseconds() / int64(r.N) +} + +// mbPerSec returns the "MB/s" metric. +func (r BenchmarkResult) mbPerSec() float64 { + if v, ok := r.Extra["MB/s"]; ok { + return v + } + if r.Bytes <= 0 || r.T <= 0 || r.N <= 0 { + return 0 + } + return (float64(r.Bytes) * float64(r.N) / 1e6) / r.T.Seconds() +} + +// AllocsPerOp returns the "allocs/op" metric, +// which is calculated as r.MemAllocs / r.N. +func (r BenchmarkResult) AllocsPerOp() int64 { + if v, ok := r.Extra["allocs/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return int64(r.MemAllocs) / int64(r.N) +} + +// AllocedBytesPerOp returns the "B/op" metric, +// which is calculated as r.MemBytes / r.N. +func (r BenchmarkResult) AllocedBytesPerOp() int64 { + if v, ok := r.Extra["B/op"]; ok { + return int64(v) + } + if r.N <= 0 { + return 0 + } + return int64(r.MemBytes) / int64(r.N) +} + +// String returns a summary of the benchmark results. +// It follows the benchmark result line format from +// https://golang.org/design/14313-benchmark-format, not including the +// benchmark name. +// Extra metrics override built-in metrics of the same name. +// String does not include allocs/op or B/op, since those are reported +// by [BenchmarkResult.MemString]. +func (r BenchmarkResult) String() string { + buf := new(strings.Builder) + fmt.Fprintf(buf, "%8d", r.N) + + // Get ns/op as a float. + ns, ok := r.Extra["ns/op"] + if !ok { + ns = float64(r.T.Nanoseconds()) / float64(r.N) + } + if ns != 0 { + buf.WriteByte('\t') + prettyPrint(buf, ns, "ns/op") + } + + if mbs := r.mbPerSec(); mbs != 0 { + fmt.Fprintf(buf, "\t%7.2f MB/s", mbs) + } + + // Print extra metrics that aren't represented in the standard + // metrics. + var extraKeys []string + for k := range r.Extra { + switch k { + case "ns/op", "MB/s", "B/op", "allocs/op": + // Built-in metrics reported elsewhere. + continue + } + extraKeys = append(extraKeys, k) + } + slices.Sort(extraKeys) + for _, k := range extraKeys { + buf.WriteByte('\t') + prettyPrint(buf, r.Extra[k], k) + } + return buf.String() +} + +func prettyPrint(w io.Writer, x float64, unit string) { + // Print all numbers with 10 places before the decimal point + // and small numbers with four sig figs. Field widths are + // chosen to fit the whole part in 10 places while aligning + // the decimal point of all fractional formats. + var format string + switch y := math.Abs(x); { + case y == 0 || y >= 999.95: + format = "%10.0f %s" + case y >= 99.995: + format = "%12.1f %s" + case y >= 9.9995: + format = "%13.2f %s" + case y >= 0.99995: + format = "%14.3f %s" + case y >= 0.099995: + format = "%15.4f %s" + case y >= 0.0099995: + format = "%16.5f %s" + case y >= 0.00099995: + format = "%17.6f %s" + default: + format = "%18.7f %s" + } + fmt.Fprintf(w, format, x, unit) +} + +// MemString returns r.AllocedBytesPerOp and r.AllocsPerOp in the same format as 'go test'. +func (r BenchmarkResult) MemString() string { + return fmt.Sprintf("%8d B/op\t%8d allocs/op", + r.AllocedBytesPerOp(), r.AllocsPerOp()) +} + +// benchmarkName returns full name of benchmark including procs suffix. +func benchmarkName(name string, n int) string { + if n != 1 { + return fmt.Sprintf("%s-%d", name, n) + } + return name +} + +type benchState struct { + match *matcher + + maxLen int // The largest recorded benchmark name. + extLen int // Maximum extension length. +} + +// RunBenchmarks is an internal function but exported because it is cross-package; +// it is part of the implementation of the "go test" command. +func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { + runBenchmarks("", matchString, benchmarks) +} + +func runBenchmarks(importPath string, matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool { + // If no flag was specified, don't run benchmarks. + if len(*matchBenchmarks) == 0 { + return true + } + // Collect matching benchmarks and determine longest name. + maxprocs := 1 + for _, procs := range cpuList { + if procs > maxprocs { + maxprocs = procs + } + } + bstate := &benchState{ + match: newMatcher(matchString, *matchBenchmarks, "-test.bench", *skip), + extLen: len(benchmarkName("", maxprocs)), + } + var bs []InternalBenchmark + for _, Benchmark := range benchmarks { + if _, matched, _ := bstate.match.fullName(nil, Benchmark.Name); matched { + bs = append(bs, Benchmark) + benchName := benchmarkName(Benchmark.Name, maxprocs) + if l := len(benchName) + bstate.extLen + 1; l > bstate.maxLen { + bstate.maxLen = l + } + } + } + main := &B{ + common: common{ + name: "Main", + w: os.Stdout, + bench: true, + }, + codspeed: codspeed{ + instrument_hooks: NewInstrumentHooks(), + }, + importPath: importPath, + benchFunc: func(b *B) { + for _, Benchmark := range bs { + b.Run(Benchmark.Name, Benchmark.F) + } + }, + benchTime: benchTime, + bstate: bstate, + } + defer main.codspeed.instrument_hooks.Close() + + if Verbose() { + main.chatty = newChattyPrinter(main.w) + } + main.runN(1) + return !main.failed +} + +// processBench runs bench b for the configured CPU counts and prints the results. +func (s *benchState) processBench(b *B) { + for i, procs := range cpuList { + for j := uint(0); j < *count; j++ { + runtime.GOMAXPROCS(procs) + benchName := benchmarkName(b.name, procs) + + // If it's chatty, we've already printed this information. + if b.chatty == nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } + // Recompute the running time for all but the first iteration. + if i > 0 || j > 0 { + b = &B{ + common: common{ + signal: make(chan bool), + name: b.name, + w: b.w, + chatty: b.chatty, + bench: true, + }, + codspeed: b.codspeed, + benchFunc: b.benchFunc, + benchTime: b.benchTime, + } + b.run1() + } + r := b.doBench() + if b.failed { + ensureBenchmarkIsStopped(b) + + // The output could be very long here, but probably isn't. + // We print it all, regardless, because we don't want to trim the reason + // the benchmark failed. + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), benchName, b.output) + continue + } + results := r.String() + saveCodspeedResults(b, r, benchName) + + if b.chatty != nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } + if *benchmarkMemory || b.showAllocResult { + results += "\t" + r.MemString() + } + fmt.Fprintln(b.w, results) + // Unlike with tests, we ignore the -chatty flag and always print output for + // benchmarks since the output generation time will skew the results. + if len(b.output) > 0 { + b.trimOutput() + fmt.Fprintf(b.w, "%s--- BENCH: %s\n%s", b.chatty.prefix(), benchName, b.output) + } + if p := runtime.GOMAXPROCS(-1); p != procs { + fmt.Fprintf(os.Stderr, "testing: %s left GOMAXPROCS set to %d\n", benchName, p) + } + if b.chatty != nil && b.chatty.json { + b.chatty.Updatef("", "=== NAME %s\n", "") + } + } + } +} + +// If hideStdoutForTesting is true, Run does not print the benchName. +// This avoids a spurious print during 'go test' on package testing itself, +// which invokes b.Run in its own tests (see sub_test.go). +var hideStdoutForTesting = false + +// Run benchmarks f as a subbenchmark with the given name. It reports +// whether there were any failures. +// +// A subbenchmark is like any other benchmark. A benchmark that calls Run at +// least once will not be measured itself and will be called once with N=1. +func (b *B) Run(name string, f func(b *B)) bool { + // Since b has subbenchmarks, we will no longer run it as a benchmark itself. + // Release the lock and acquire it on exit to ensure locks stay paired. + b.hasSub.Store(true) + benchmarkLock.Unlock() + defer benchmarkLock.Lock() + + benchName, ok, partial := b.name, true, false + if b.bstate != nil { + benchName, ok, partial = b.bstate.match.fullName(&b.common, name) + } + if !ok { + return true + } + var pc [maxStackLen]uintptr + n := runtime.Callers(2, pc[:]) + sub := &B{ + common: common{ + signal: make(chan bool), + name: benchName, + parent: &b.common, + level: b.level + 1, + creator: pc[:n], + w: b.w, + chatty: b.chatty, + bench: true, + }, + codspeed: b.codspeed, + importPath: b.importPath, + benchFunc: f, + benchTime: b.benchTime, + bstate: b.bstate, + } + if partial { + // Partial name match, like -bench=X/Y matching BenchmarkX. + // Only process sub-benchmarks, if any. + sub.hasSub.Store(true) + } + + if b.chatty != nil { + labelsOnce.Do(func() { + fmt.Printf("goos: %s\n", runtime.GOOS) + fmt.Printf("goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { + fmt.Printf("pkg: %s\n", b.importPath) + } + if cpu := sysinfo.CPUName(); cpu != "" { + fmt.Printf("cpu: %s\n", cpu) + } + }) + + if !hideStdoutForTesting { + if b.chatty.json { + b.chatty.Updatef(benchName, "=== RUN %s\n", benchName) + } + fmt.Println(benchName) + } + } + + if sub.run1() { + sub.run() + } + b.add(sub.result) + return !sub.failed +} + +// add simulates running benchmarks in sequence in a single iteration. It is +// used to give some meaningful results in case func Benchmark is used in +// combination with Run. +func (b *B) add(other BenchmarkResult) { + r := &b.result + // The aggregated BenchmarkResults resemble running all subbenchmarks as + // in sequence in a single benchmark. + r.N = 1 + r.T += time.Duration(other.NsPerOp()) + if other.Bytes == 0 { + // Summing Bytes is meaningless in aggregate if not all subbenchmarks + // set it. + b.missingBytes = true + r.Bytes = 0 + } + if !b.missingBytes { + r.Bytes += other.Bytes + } + r.MemAllocs += uint64(other.AllocsPerOp()) + r.MemBytes += uint64(other.AllocedBytesPerOp()) +} + +// trimOutput shortens the output from a benchmark, which can be very long. +func (b *B) trimOutput() { + // The output is likely to appear multiple times because the benchmark + // is run multiple times, but at least it will be seen. This is not a big deal + // because benchmarks rarely print, but just in case, we trim it if it's too long. + const maxNewlines = 10 + for nlCount, j := 0, 0; j < len(b.output); j++ { + if b.output[j] == '\n' { + nlCount++ + if nlCount >= maxNewlines { + b.output = append(b.output[:j], "\n\t... [output truncated]\n"...) + break + } + } + } +} + +// A PB is used by RunParallel for running parallel benchmarks. +type PB struct { + globalN *atomic.Uint64 // shared between all worker goroutines iteration counter + grain uint64 // acquire that many iterations from globalN at once + cache uint64 // local cache of acquired iterations + bN uint64 // total number of iterations to execute (b.N) +} + +// Next reports whether there are more iterations to execute. +func (pb *PB) Next() bool { + if pb.cache == 0 { + n := pb.globalN.Add(pb.grain) + if n <= pb.bN { + pb.cache = pb.grain + } else if n < pb.bN+pb.grain { + pb.cache = pb.bN + pb.grain - n + } else { + return false + } + } + pb.cache-- + return true +} + +// RunParallel runs a benchmark in parallel. +// It creates multiple goroutines and distributes b.N iterations among them. +// The number of goroutines defaults to GOMAXPROCS. To increase parallelism for +// non-CPU-bound benchmarks, call [B.SetParallelism] before RunParallel. +// RunParallel is usually used with the go test -cpu flag. +// +// The body function will be run in each goroutine. It should set up any +// goroutine-local state and then iterate until pb.Next returns false. +// It should not use the [B.StartTimer], [B.StopTimer], or [B.ResetTimer] functions, +// because they have global effect. It should also not call [B.Run]. +// +// RunParallel reports ns/op values as wall time for the benchmark as a whole, +// not the sum of wall time or CPU time over each parallel goroutine. +func (b *B) RunParallel(body func(*PB)) { + if b.N == 0 { + return // Nothing to do when probing. + } + // Calculate grain size as number of iterations that take ~100µs. + // 100µs is enough to amortize the overhead and provide sufficient + // dynamic load balancing. + grain := uint64(0) + if b.previousN > 0 && b.previousDuration > 0 { + grain = 1e5 * uint64(b.previousN) / uint64(b.previousDuration) + } + if grain < 1 { + grain = 1 + } + // We expect the inner loop and function call to take at least 10ns, + // so do not do more than 100µs/10ns=1e4 iterations. + if grain > 1e4 { + grain = 1e4 + } + + var n atomic.Uint64 + numProcs := b.parallelism * runtime.GOMAXPROCS(0) + var wg sync.WaitGroup + wg.Add(numProcs) + for p := 0; p < numProcs; p++ { + go func() { + defer wg.Done() + pb := &PB{ + globalN: &n, + grain: grain, + bN: uint64(b.N), + } + body(pb) + }() + } + wg.Wait() + if n.Load() <= uint64(b.N) && !b.Failed() { + b.Fatal("RunParallel: body exited without pb.Next() == false") + } +} + +// SetParallelism sets the number of goroutines used by [B.RunParallel] to p*GOMAXPROCS. +// There is usually no need to call SetParallelism for CPU-bound benchmarks. +// If p is less than 1, this call will have no effect. +func (b *B) SetParallelism(p int) { + if p >= 1 { + b.parallelism = p + } +} + +// Benchmark benchmarks a single function. It is useful for creating +// custom benchmarks that do not use the "go test" command. +// +// If f depends on testing flags, then [Init] must be used to register +// those flags before calling Benchmark and before calling [flag.Parse]. +// +// If f calls Run, the result will be an estimate of running all its +// subbenchmarks that don't call Run in sequence in a single benchmark. +func Benchmark(f func(b *B)) BenchmarkResult { + b := &B{ + common: common{ + signal: make(chan bool), + w: discard{}, + }, + benchFunc: f, + benchTime: benchTime, + } + if b.run1() { + b.run() + } + return b.result +} + +type discard struct{} + +func (discard) Write(b []byte) (n int, err error) { return len(b), nil } diff --git a/go-runner/overlay/benchmark1.24.0.patch b/go-runner/overlay/benchmark1.24.0.patch new file mode 100644 index 00000000..d24fcf31 --- /dev/null +++ b/go-runner/overlay/benchmark1.24.0.patch @@ -0,0 +1,354 @@ +--- benchmark.go.1.24 2026-01-09 11:59:54.625882898 +0100 ++++ overlay/benchmark1.24.go 2026-01-09 12:30:27.328634216 +0100 +@@ -93,6 +93,7 @@ + // affecting benchmark results. + type B struct { + common ++ codspeed + importPath string // import path of the package containing the benchmark + bstate *benchState + N int +@@ -132,31 +133,24 @@ + } + } + +-// StartTimer starts timing a test. This function is called automatically +-// before a benchmark starts, but it can also be used to resume timing after +-// a call to [B.StopTimer]. + func (b *B) StartTimer() { +- if !b.timerOn { +- runtime.ReadMemStats(&memStats) +- b.startAllocs = memStats.Mallocs +- b.startBytes = memStats.TotalAlloc +- b.start = highPrecisionTimeNow() +- b.timerOn = true +- b.loop.i &^= loopPoisonTimer ++ timerOn := b.timerOn ++ ++ b.StartTimerWithoutMarker() ++ ++ if !timerOn { ++ b.startTimestamp = CurrentTimestamp() + } + } + +-// StopTimer stops timing a test. This can be used to pause the timer +-// while performing steps that you don't want to measure. + func (b *B) StopTimer() { +- if b.timerOn { +- b.duration += highPrecisionTimeSince(b.start) +- runtime.ReadMemStats(&memStats) +- b.netAllocs += memStats.Mallocs - b.startAllocs +- b.netBytes += memStats.TotalAlloc - b.startBytes +- b.timerOn = false +- // If we hit B.Loop with the timer stopped, fail. +- b.loop.i |= loopPoisonTimer ++ endTimestamp := CurrentTimestamp() ++ timerOn := b.timerOn ++ ++ b.StopTimerWithoutMarker() ++ ++ if timerOn { ++ b.AddBenchmarkMarkers(endTimestamp) + } + } + +@@ -176,10 +170,18 @@ + b.startAllocs = memStats.Mallocs + b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() ++ ++ b.startTimestamp = CurrentTimestamp() + } + b.duration = 0 + b.netAllocs = 0 + b.netBytes = 0 ++ ++ // Clear CodSpeed timestamp data ++ b.codspeedItersPerRound = b.codspeedItersPerRound[:0] ++ b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] ++ b.startTimestamps = b.startTimestamps[:0] ++ b.stopTimestamps = b.stopTimestamps[:0] + } + + // SetBytes records the number of bytes processed in a single operation. +@@ -195,6 +197,11 @@ + + // runN runs a single benchmark for the specified number of iterations. + func (b *B) runN(n int) { ++ b.__codspeed_root_frame__runN(n) ++} ++ ++//go:noinline ++func (b *B) __codspeed_root_frame__runN(n int) { + benchmarkLock.Lock() + defer benchmarkLock.Unlock() + ctx, cancelCtx := context.WithCancel(context.Background()) +@@ -218,6 +225,7 @@ + b.StartTimer() + b.benchFunc(b) + b.StopTimer() ++ b.SaveMeasurement() + b.previousN = n + b.previousDuration = b.duration + +@@ -246,6 +254,8 @@ + }() + <-b.signal + if b.failed { ++ // This case can happen with a `b.Loop()` benchmark if any of the iterations fail ++ ensureBenchmarkIsStopped(b) + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) + return false + } +@@ -274,6 +284,8 @@ + // subbenchmarks. b must not have subbenchmarks. + func (b *B) run() { + labelsOnce.Do(func() { ++ fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") ++ + fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) + fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { +@@ -344,18 +356,48 @@ + b.runN(b.benchTime.n) + } + } else { +- d := b.benchTime.d +- for n := int64(1); !b.failed && b.duration < d && n < 1e9; { ++ warmupD := b.benchTime.d / 10 ++ warmupN := int64(1) ++ for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { + last := n + // Predict required iterations. +- goalns := d.Nanoseconds() ++ goalns := warmupD.Nanoseconds() + prevIters := int64(b.N) + n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) + b.runN(int(n)) ++ warmupN = n ++ } ++ ++ // Reset the fields from the warmup run ++ b.ResetTimer() ++ ++ // Final run: ++ benchD := b.benchTime.d ++ benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) ++ ++ // When we have a very slow benchmark (e.g. taking 500ms), we have to: ++ // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) ++ // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds ++ const minRounds = 100 ++ var rounds int ++ var roundN int ++ if benchN < minRounds { ++ rounds = benchN ++ roundN = 1 ++ } else { ++ rounds = minRounds ++ roundN = benchN / int(rounds) ++ } ++ ++ b.codspeed.instrument_hooks.StartBenchmark() ++ for range rounds { ++ b.runN(int(roundN)) + } ++ b.codspeed.instrument_hooks.StopBenchmark() ++ b.sendAccumulatedTimestamps() + } + } +- b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.extra} ++ b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} + } + + // Elapsed returns the measured elapsed time of the benchmark. +@@ -391,11 +433,7 @@ + func (b *B) stopOrScaleBLoop() bool { + t := b.Elapsed() + if t >= b.benchTime.d { +- // Stop the timer so we don't count cleanup time +- b.StopTimer() +- // Commit iteration count +- b.N = int(b.loop.n) +- b.loop.done = true ++ // We've reached the target + return false + } + // Loop scaling +@@ -407,45 +445,78 @@ + // in big trouble. + panic("loop iteration target overflow") + } +- b.loop.i++ + return true + } + + func (b *B) loopSlowPath() bool { + // Consistency checks +- if !b.timerOn { +- b.Fatal("B.Loop called with timer stopped") +- } ++ // if !b.timerOn { ++ // b.Fatal("B.Loop called with timer stopped") ++ // } + if b.loop.i&loopPoisonMask != 0 { + panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) + } + + if b.loop.n == 0 { +- // If it's the first call to b.Loop() in the benchmark function. +- // Allows more precise measurement of benchmark loop cost counts. +- // Also initialize target to 1 to kick start loop scaling. +- b.loop.n = 1 ++ // It's the first call to b.Loop() in the benchmark function. ++ if b.benchTime.n > 0 { ++ // Fixed iteration count. ++ b.loop.n = uint64(b.benchTime.n) ++ } else { ++ // Initialize target to 1 to kick start loop scaling. ++ b.loop.n = 1 ++ } + // Within a b.Loop loop, we don't use b.N (to avoid confusion). + b.N = 0 +- b.loop.i++ ++ b.codspeed.instrument_hooks.StartBenchmark() + b.ResetTimer() ++ b.StartTimerWithoutMarker() ++ ++ // Start the next iteration. ++ b.loop.i++ + return true + } +- // Handles fixed iterations case ++ ++ // Should we keep iterating? ++ var more bool + if b.benchTime.n > 0 { +- if b.loop.n < uint64(b.benchTime.n) { +- b.loop.n = uint64(b.benchTime.n) +- b.loop.i++ +- return true ++ // The iteration count is fixed, so we should have run this many and now ++ // be done. ++ if b.loop.i != uint64(b.benchTime.n) { ++ // We shouldn't be able to reach the slow path in this case. ++ panic(fmt.Sprintf("iteration count %d < fixed target %d", b.loop.i, b.benchTime.n)) + } +- b.StopTimer() ++ more = false ++ } else { ++ // Handle fixed time case ++ more = b.stopOrScaleBLoop() ++ } ++ if !more { ++ // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function ++ // but this will result in a huge performance degradation since the C FFI calls are expensive. ++ // ++ // The only downside of having this here, is that there's a small chance of perf sampling the ++ // benchmark framework code which already happens anyway because we only emit 1 pair of ++ // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. ++ endTimestamp := CurrentTimestamp() ++ ++ // Edge case: The timer is stopped in b.Loop() which prevents any further calls to ++ // StopTimer() from adding the benchmark markers. We have to manually submit them here, ++ // once the benchmark loop is done. ++ b.AddBenchmarkMarkers(endTimestamp) ++ b.codspeed.instrument_hooks.StopBenchmark() ++ b.sendAccumulatedTimestamps() ++ + // Commit iteration count + b.N = int(b.loop.n) + b.loop.done = true + return false + } +- // Handles fixed time case +- return b.stopOrScaleBLoop() ++ ++ b.StartTimerWithoutMarker() ++ // Start the next iteration. ++ b.loop.i++ ++ return true + } + + // Loop returns true as long as the benchmark should continue running. +@@ -482,6 +553,8 @@ + // whereas b.N-based benchmarks must run the benchmark function (and any + // associated setup and cleanup) several times. + func (b *B) Loop() bool { ++ b.StopTimerWithoutMarker() ++ b.SaveMeasurement() + // This is written such that the fast path is as fast as possible and can be + // inlined. + // +@@ -496,6 +569,7 @@ + // path can do consistency checks and fail. + if b.loop.i < b.loop.n { + b.loop.i++ ++ b.StartTimerWithoutMarker() + return true + } + return b.loopSlowPath() +@@ -522,6 +596,9 @@ + MemAllocs uint64 // The total number of memory allocations. + MemBytes uint64 // The total number of bytes allocated. + ++ CodspeedTimePerRoundNs []time.Duration ++ CodspeedItersPerRound []int64 ++ + // Extra records additional metrics reported by ReportMetric. + Extra map[string]float64 + } +@@ -702,6 +779,9 @@ + w: os.Stdout, + bench: true, + }, ++ codspeed: codspeed{ ++ instrument_hooks: NewInstrumentHooks(), ++ }, + importPath: importPath, + benchFunc: func(b *B) { + for _, Benchmark := range bs { +@@ -711,6 +791,8 @@ + benchTime: benchTime, + bstate: bstate, + } ++ defer main.codspeed.instrument_hooks.Close() ++ + if Verbose() { + main.chatty = newChattyPrinter(main.w) + } +@@ -739,6 +821,7 @@ + chatty: b.chatty, + bench: true, + }, ++ codspeed: b.codspeed, + benchFunc: b.benchFunc, + benchTime: b.benchTime, + } +@@ -746,6 +829,8 @@ + } + r := b.doBench() + if b.failed { ++ ensureBenchmarkIsStopped(b) ++ + // The output could be very long here, but probably isn't. + // We print it all, regardless, because we don't want to trim the reason + // the benchmark failed. +@@ -753,6 +838,8 @@ + continue + } + results := r.String() ++ saveCodspeedResults(b, r, benchName) ++ + if b.chatty != nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } +@@ -813,6 +900,7 @@ + chatty: b.chatty, + bench: true, + }, ++ codspeed: b.codspeed, + importPath: b.importPath, + benchFunc: f, + benchTime: b.benchTime, diff --git a/go-runner/overlay/benchmark.go b/go-runner/overlay/benchmark1.25.0.go similarity index 92% rename from go-runner/overlay/benchmark.go rename to go-runner/overlay/benchmark1.25.0.go index 16e1aebd..8fcb1d45 100644 --- a/go-runner/overlay/benchmark.go +++ b/go-runner/overlay/benchmark1.25.0.go @@ -78,21 +78,6 @@ type InternalBenchmark struct { F func(b *B) } -type codspeed struct { - instrument_hooks *InstrumentHooks - - codspeedTimePerRoundNs []time.Duration - codspeedItersPerRound []int64 - - startTimestamp uint64 - startTimestamps []uint64 - stopTimestamps []uint64 - - // Indicates whether a measurement has been saved already. This aims to prevent saving measurements - // twice, because `b.Loop()` saves them internally as well but is also called from runN - savedMeasurement bool -} - // B is a type passed to [Benchmark] functions to manage benchmark // timing and control the number of iterations. // @@ -148,21 +133,6 @@ type B struct { } } -// StartTimer starts timing a test. This function is called automatically -// before a benchmark starts, but it can also be used to resume timing after -// a call to [B.StopTimer]. -func (b *B) StartTimerWithoutMarker() { - if !b.timerOn { - // runtime.ReadMemStats(&memStats) - // b.startAllocs = memStats.Mallocs - // b.startBytes = memStats.TotalAlloc - b.start = highPrecisionTimeNow() - b.timerOn = true - b.savedMeasurement = false - // b.loop.i &^= loopPoisonTimer - } -} - func (b *B) StartTimer() { timerOn := b.timerOn @@ -173,52 +143,6 @@ func (b *B) StartTimer() { } } -// StopTimer stops timing a test. This can be used to pause the timer -// while performing steps that you don't want to measure. -func (b *B) StopTimerWithoutMarker() { - if b.timerOn { - timeSinceStart := highPrecisionTimeSince(b.start) - b.duration += timeSinceStart - // runtime.ReadMemStats(&memStats) - // b.netAllocs += memStats.Mallocs - b.startAllocs - // b.netBytes += memStats.TotalAlloc - b.startBytes - b.timerOn = false - // If we hit B.Loop with the timer stopped, fail. - // b.loop.i |= loopPoisonTimer - } -} - -func (b *B) SaveMeasurement() { - if b.savedMeasurement { - return - } - b.savedMeasurement = true - - // WARN: This function must not be called if the timer is on, because we - // would read an incomplete b.duration value. - if b.timerOn { - panic("SaveMeasurement called with timer on") - } - - // For b.N loops: This will be called in runN which sets b.N to the number of iterations. - // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since - // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as - // the number of iterations for this round. - timeSinceStart := highPrecisionTimeSince(b.start) - - // If this gets called from b.Loop(), we have to take the duration compared to the previous StartTimer, - // if it's called from runN, we can use b.duration - duration := time.Duration(0) - if b.N == 0 { - duration = timeSinceStart - } else { - duration = b.duration - } - - b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) - b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, duration) -} - func (b *B) StopTimer() { endTimestamp := CurrentTimestamp() timerOn := b.timerOn @@ -260,17 +184,6 @@ func (b *B) ResetTimer() { b.stopTimestamps = b.stopTimestamps[:0] } -func (b *B) sendAccumulatedTimestamps() { - for i := 0; i < len(b.startTimestamps); i++ { - b.instrument_hooks.AddBenchmarkTimestamps( - b.startTimestamps[i], - b.stopTimestamps[i], - ) - } - b.startTimestamps = b.startTimestamps[:0] - b.stopTimestamps = b.stopTimestamps[:0] -} - // SetBytes records the number of bytes processed in a single operation. // If this is called, the benchmark will report ns/op and MB/s. func (b *B) SetBytes(n int64) { b.bytes = n } diff --git a/go-runner/overlay/benchmark1.25.0.patch b/go-runner/overlay/benchmark1.25.0.patch new file mode 100644 index 00000000..6ed5443a --- /dev/null +++ b/go-runner/overlay/benchmark1.25.0.patch @@ -0,0 +1,298 @@ +--- benchmark.go 2026-01-09 11:36:51.153087761 +0100 ++++ overlay/benchmark1.25.go 2026-01-09 11:58:31.662387782 +0100 +@@ -93,6 +93,7 @@ + // affecting benchmark results. + type B struct { + common ++ codspeed + importPath string // import path of the package containing the benchmark + bstate *benchState + N int +@@ -132,31 +133,24 @@ + } + } + +-// StartTimer starts timing a test. This function is called automatically +-// before a benchmark starts, but it can also be used to resume timing after +-// a call to [B.StopTimer]. + func (b *B) StartTimer() { +- if !b.timerOn { +- runtime.ReadMemStats(&memStats) +- b.startAllocs = memStats.Mallocs +- b.startBytes = memStats.TotalAlloc +- b.start = highPrecisionTimeNow() +- b.timerOn = true +- b.loop.i &^= loopPoisonTimer ++ timerOn := b.timerOn ++ ++ b.StartTimerWithoutMarker() ++ ++ if !timerOn { ++ b.startTimestamp = CurrentTimestamp() + } + } + +-// StopTimer stops timing a test. This can be used to pause the timer +-// while performing steps that you don't want to measure. + func (b *B) StopTimer() { +- if b.timerOn { +- b.duration += highPrecisionTimeSince(b.start) +- runtime.ReadMemStats(&memStats) +- b.netAllocs += memStats.Mallocs - b.startAllocs +- b.netBytes += memStats.TotalAlloc - b.startBytes +- b.timerOn = false +- // If we hit B.Loop with the timer stopped, fail. +- b.loop.i |= loopPoisonTimer ++ endTimestamp := CurrentTimestamp() ++ timerOn := b.timerOn ++ ++ b.StopTimerWithoutMarker() ++ ++ if timerOn { ++ b.AddBenchmarkMarkers(endTimestamp) + } + } + +@@ -176,10 +170,18 @@ + b.startAllocs = memStats.Mallocs + b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() ++ ++ b.startTimestamp = CurrentTimestamp() + } + b.duration = 0 + b.netAllocs = 0 + b.netBytes = 0 ++ ++ // Clear CodSpeed timestamp data ++ b.codspeedItersPerRound = b.codspeedItersPerRound[:0] ++ b.codspeedTimePerRoundNs = b.codspeedTimePerRoundNs[:0] ++ b.startTimestamps = b.startTimestamps[:0] ++ b.stopTimestamps = b.stopTimestamps[:0] + } + + // SetBytes records the number of bytes processed in a single operation. +@@ -195,6 +197,11 @@ + + // runN runs a single benchmark for the specified number of iterations. + func (b *B) runN(n int) { ++ b.__codspeed_root_frame__runN(n) ++} ++ ++//go:noinline ++func (b *B) __codspeed_root_frame__runN(n int) { + benchmarkLock.Lock() + defer benchmarkLock.Unlock() + ctx, cancelCtx := context.WithCancel(context.Background()) +@@ -218,6 +225,7 @@ + b.StartTimer() + b.benchFunc(b) + b.StopTimer() ++ b.SaveMeasurement() + b.previousN = n + b.previousDuration = b.duration + +@@ -246,6 +254,8 @@ + }() + <-b.signal + if b.failed { ++ // This case can happen with a `b.Loop()` benchmark if any of the iterations fail ++ ensureBenchmarkIsStopped(b) + fmt.Fprintf(b.w, "%s--- FAIL: %s\n%s", b.chatty.prefix(), b.name, b.output) + return false + } +@@ -274,6 +284,8 @@ + // subbenchmarks. b must not have subbenchmarks. + func (b *B) run() { + labelsOnce.Do(func() { ++ fmt.Fprintf(b.w, "Running with CodSpeed (mode: walltime)\n") ++ + fmt.Fprintf(b.w, "goos: %s\n", runtime.GOOS) + fmt.Fprintf(b.w, "goarch: %s\n", runtime.GOARCH) + if b.importPath != "" { +@@ -344,18 +356,48 @@ + b.runN(b.benchTime.n) + } + } else { +- d := b.benchTime.d +- for n := int64(1); !b.failed && b.duration < d && n < 1e9; { ++ warmupD := b.benchTime.d / 10 ++ warmupN := int64(1) ++ for n := int64(1); !b.failed && b.duration < warmupD && n < 1e9; { + last := n + // Predict required iterations. +- goalns := d.Nanoseconds() ++ goalns := warmupD.Nanoseconds() + prevIters := int64(b.N) + n = int64(predictN(goalns, prevIters, b.duration.Nanoseconds(), last)) + b.runN(int(n)) ++ warmupN = n + } ++ ++ // Reset the fields from the warmup run ++ b.ResetTimer() ++ ++ // Final run: ++ benchD := b.benchTime.d ++ benchN := predictN(benchD.Nanoseconds(), int64(b.N), b.duration.Nanoseconds(), warmupN) ++ ++ // When we have a very slow benchmark (e.g. taking 500ms), we have to: ++ // 1. Reduce the number of rounds to not slow down the process (e.g. by executing a 1s bench 100 times) ++ // 2. Not end up with roundN of 0 when dividing benchN (which can be < 100) by rounds ++ const minRounds = 100 ++ var rounds int ++ var roundN int ++ if benchN < minRounds { ++ rounds = benchN ++ roundN = 1 ++ } else { ++ rounds = minRounds ++ roundN = benchN / int(rounds) ++ } ++ ++ b.codspeed.instrument_hooks.StartBenchmark() ++ for range rounds { ++ b.runN(int(roundN)) ++ } ++ b.codspeed.instrument_hooks.StopBenchmark() ++ b.sendAccumulatedTimestamps() + } + } +- b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.extra} ++ b.result = BenchmarkResult{b.N, b.duration, b.bytes, b.netAllocs, b.netBytes, b.codspeedTimePerRoundNs, b.codspeedItersPerRound, b.extra} + } + + // Elapsed returns the measured elapsed time of the benchmark. +@@ -408,9 +450,9 @@ + + func (b *B) loopSlowPath() bool { + // Consistency checks +- if !b.timerOn { +- b.Fatal("B.Loop called with timer stopped") +- } ++ // if !b.timerOn { ++ // b.Fatal("B.Loop called with timer stopped") ++ // } + if b.loop.i&loopPoisonMask != 0 { + panic(fmt.Sprintf("unknown loop stop condition: %#x", b.loop.i)) + } +@@ -426,7 +468,9 @@ + } + // Within a b.Loop loop, we don't use b.N (to avoid confusion). + b.N = 0 ++ b.codspeed.instrument_hooks.StartBenchmark() + b.ResetTimer() ++ b.StartTimerWithoutMarker() + + // Start the next iteration. + b.loop.i++ +@@ -448,13 +492,28 @@ + more = b.stopOrScaleBLoop() + } + if !more { +- b.StopTimer() ++ // NOTE: We could move the endTimestamp capturing further up or even into the Loop() function ++ // but this will result in a huge performance degradation since the C FFI calls are expensive. ++ // ++ // The only downside of having this here, is that there's a small chance of perf sampling the ++ // benchmark framework code which already happens anyway because we only emit 1 pair of ++ // start/stop markers per benchmark to minimize overhead and allow full flamegraphs. ++ endTimestamp := CurrentTimestamp() ++ ++ // Edge case: The timer is stopped in b.Loop() which prevents any further calls to ++ // StopTimer() from adding the benchmark markers. We have to manually submit them here, ++ // once the benchmark loop is done. ++ b.AddBenchmarkMarkers(endTimestamp) ++ b.codspeed.instrument_hooks.StopBenchmark() ++ b.sendAccumulatedTimestamps() ++ + // Commit iteration count + b.N = int(b.loop.n) + b.loop.done = true + return false + } + ++ b.StartTimerWithoutMarker() + // Start the next iteration. + b.loop.i++ + return true +@@ -495,6 +554,8 @@ + // whereas b.N-based benchmarks must run the benchmark function (and any + // associated setup and cleanup) several times. + func (b *B) Loop() bool { ++ b.StopTimerWithoutMarker() ++ b.SaveMeasurement() + // This is written such that the fast path is as fast as possible and can be + // inlined. + // +@@ -509,6 +570,7 @@ + // path can do consistency checks and fail. + if b.loop.i < b.loop.n { + b.loop.i++ ++ b.StartTimerWithoutMarker() + return true + } + return b.loopSlowPath() +@@ -535,6 +597,9 @@ + MemAllocs uint64 // The total number of memory allocations. + MemBytes uint64 // The total number of bytes allocated. + ++ CodspeedTimePerRoundNs []time.Duration ++ CodspeedItersPerRound []int64 ++ + // Extra records additional metrics reported by ReportMetric. + Extra map[string]float64 + } +@@ -715,6 +780,9 @@ + w: os.Stdout, + bench: true, + }, ++ codspeed: codspeed{ ++ instrument_hooks: NewInstrumentHooks(), ++ }, + importPath: importPath, + benchFunc: func(b *B) { + for _, Benchmark := range bs { +@@ -724,6 +792,8 @@ + benchTime: benchTime, + bstate: bstate, + } ++ defer main.codspeed.instrument_hooks.Close() ++ + if Verbose() { + main.chatty = newChattyPrinter(main.w) + } +@@ -752,6 +822,7 @@ + chatty: b.chatty, + bench: true, + }, ++ codspeed: b.codspeed, + benchFunc: b.benchFunc, + benchTime: b.benchTime, + } +@@ -760,6 +831,8 @@ + } + r := b.doBench() + if b.failed { ++ ensureBenchmarkIsStopped(b) ++ + // The output could be very long here, but probably isn't. + // We print it all, regardless, because we don't want to trim the reason + // the benchmark failed. +@@ -767,6 +840,8 @@ + continue + } + results := r.String() ++ saveCodspeedResults(b, r, benchName) ++ + if b.chatty != nil { + fmt.Fprintf(b.w, "%-*s\t", s.maxLen, benchName) + } +@@ -827,6 +902,7 @@ + chatty: b.chatty, + bench: true, + }, ++ codspeed: b.codspeed, + importPath: b.importPath, + benchFunc: f, + benchTime: b.benchTime, diff --git a/go-runner/overlay/codspeed.go b/go-runner/overlay/codspeed.go index 8e9180f9..a0de8b3a 100644 --- a/go-runner/overlay/codspeed.go +++ b/go-runner/overlay/codspeed.go @@ -13,6 +13,21 @@ import ( "time" ) +type codspeed struct { + instrument_hooks *InstrumentHooks + + codspeedTimePerRoundNs []time.Duration + codspeedItersPerRound []int64 + + startTimestamp uint64 + startTimestamps []uint64 + stopTimestamps []uint64 + + // Indicates whether a measurement has been saved already. This aims to prevent saving measurements + // twice, because `b.Loop()` saves them internally as well but is also called from runN + savedMeasurement bool +} + func findGitRoot() (string, error) { cwd, err := os.Getwd() if err != nil { @@ -181,3 +196,75 @@ func saveCodspeedResults(b *B, r BenchmarkResult, benchName string) { // Send pid and executed benchmark to the runner b.codspeed.instrument_hooks.SetExecutedBenchmark(uint32(os.Getpid()), benchUri) } + +func (b *B) sendAccumulatedTimestamps() { + for i := 0; i < len(b.startTimestamps); i++ { + b.instrument_hooks.AddBenchmarkTimestamps( + b.startTimestamps[i], + b.stopTimestamps[i], + ) + } + b.startTimestamps = b.startTimestamps[:0] + b.stopTimestamps = b.stopTimestamps[:0] +} + +func (b *B) SaveMeasurement() { + if b.savedMeasurement { + return + } + b.savedMeasurement = true + + // WARN: This function must not be called if the timer is on, because we + // would read an incomplete b.duration value. + if b.timerOn { + panic("SaveMeasurement called with timer on") + } + + // For b.N loops: This will be called in runN which sets b.N to the number of iterations. + // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since + // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as + // the number of iterations for this round. + timeSinceStart := highPrecisionTimeSince(b.start) + + // If this gets called from b.Loop(), we have to take the duration compared to the previous StartTimer, + // if it's called from runN, we can use b.duration + duration := time.Duration(0) + if b.N == 0 { + duration = timeSinceStart + } else { + duration = b.duration + } + + b.codspeedItersPerRound = append(b.codspeedItersPerRound, max(int64(b.N), 1)) + b.codspeedTimePerRoundNs = append(b.codspeedTimePerRoundNs, duration) +} + +// StopTimer stops timing a test. This can be used to pause the timer +// while performing steps that you don't want to measure. +func (b *B) StopTimerWithoutMarker() { + if b.timerOn { + timeSinceStart := highPrecisionTimeSince(b.start) + b.duration += timeSinceStart + // runtime.ReadMemStats(&memStats) + // b.netAllocs += memStats.Mallocs - b.startAllocs + // b.netBytes += memStats.TotalAlloc - b.startBytes + b.timerOn = false + // If we hit B.Loop with the timer stopped, fail. + // b.loop.i |= loopPoisonTimer + } +} + +// StartTimer starts timing a test. This function is called automatically +// before a benchmark starts, but it can also be used to resume timing after +// a call to [B.StopTimer]. +func (b *B) StartTimerWithoutMarker() { + if !b.timerOn { + // runtime.ReadMemStats(&memStats) + // b.startAllocs = memStats.Mallocs + // b.startBytes = memStats.TotalAlloc + b.start = highPrecisionTimeNow() + b.timerOn = true + b.savedMeasurement = false + // b.loop.i &^= loopPoisonTimer + } +} diff --git a/go-runner/src/runner/overlay/mod.rs b/go-runner/src/runner/overlay/mod.rs index 79d61407..8ffcb2a0 100644 --- a/go-runner/src/runner/overlay/mod.rs +++ b/go-runner/src/runner/overlay/mod.rs @@ -1,4 +1,5 @@ use anyhow::{bail, ensure}; +use semver::Version; use std::{ collections::HashMap, path::{Path, PathBuf}, @@ -9,10 +10,6 @@ use tempfile::TempDir; mod instrument_hooks; const OVERLAY_TEMPLATES: &[(&str, &str)] = &[ - ( - "benchmark.go", - include_str!("../../../overlay/benchmark.go"), - ), ("codspeed.go", include_str!("../../../overlay/codspeed.go")), ( "instrument-hooks.go", @@ -27,6 +24,16 @@ fn get_overlay_files( let instrument_hooks_dir = instrument_hooks::download_instrument_hooks(temp_dir)?; let mut files = HashMap::new(); + + // Select the appropriate benchmark file based on Go version + let content = if detect_go_version()? >= Version::new(1, 25, 0) { + include_str!("../../../overlay/benchmark1.25.0.go") + } else { + include_str!("../../../overlay/benchmark1.24.0.go") + }; + files.insert("benchmark.go".to_string(), content.to_string()); + + // Add other overlay files for (file_name, content) in OVERLAY_TEMPLATES { let content = content .replace( @@ -86,3 +93,18 @@ fn find_goroot() -> anyhow::Result { Ok(path) } + +fn detect_go_version() -> anyhow::Result { + let output = Command::new("go").args(["env", "GOVERSION"]).output()?; + if !output.status.success() { + bail!("Failed to get Go version"); + } + let version_str = String::from_utf8_lossy(&output.stdout).trim().to_string(); + + // Remove "go" prefix (e.g., "go1.25.2" -> "1.25.2") + let version_str = version_str + .strip_prefix("go") + .ok_or_else(|| anyhow::anyhow!("Invalid Go version format: {}", version_str))?; + + Ok(Version::parse(version_str)?) +} From ae27a52e1903636861c4c62c8e9be1343d730c37 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 12:28:01 +0100 Subject: [PATCH 11/13] fix(go-runner): run tests using `go` executable This avoid infinite recursions since the runner tries to intercept and forward `go test` executions to the `go-runner` --- go-runner/src/runner/mod.rs | 20 ++++++++++++++++++-- go-runner/src/runner/overlay/mod.rs | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/go-runner/src/runner/mod.rs b/go-runner/src/runner/mod.rs index c51d1dee..c435a277 100644 --- a/go-runner/src/runner/mod.rs +++ b/go-runner/src/runner/mod.rs @@ -1,6 +1,9 @@ use crate::cli::Cli; use crate::prelude::*; -use std::{path::Path, process::Command}; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; use tempfile::TempDir; mod overlay; @@ -12,8 +15,12 @@ fn run_cmd>( ) -> anyhow::Result<(TempDir, Command)> { let (_dir, overlay_file) = overlay::get_overlay_file(profile_dir.as_ref())?; + // Execute the `go test` command using the go binary, rather than the one in the PATH + // to avoid running into infinite loops with the runner which tries to intercept `go test`. + let go_binary = find_go_binary()?; + // Convert the CLI struct into a command: - let mut cmd = Command::new("go"); + let mut cmd = Command::new(go_binary); cmd.args([ "test", "-overlay", @@ -75,3 +82,12 @@ pub fn run>(profile_dir: P, dir: P, cli: &Cli) -> anyhow::Result< check_success(&output).map(|_| ()) } + +fn find_go_binary() -> anyhow::Result { + let go_binary = overlay::find_goroot()?.join("bin").join("go"); + if !go_binary.exists() { + bail!("Go binary doesn't exist at: {:?}", go_binary); + } + + Ok(go_binary) +} diff --git a/go-runner/src/runner/overlay/mod.rs b/go-runner/src/runner/overlay/mod.rs index 8ffcb2a0..95028f5c 100644 --- a/go-runner/src/runner/overlay/mod.rs +++ b/go-runner/src/runner/overlay/mod.rs @@ -79,7 +79,7 @@ pub fn get_overlay_file(profile_dir: &Path) -> anyhow::Result<(TempDir, PathBuf) Ok((overlay_dir, overlay_file)) } -fn find_goroot() -> anyhow::Result { +pub fn find_goroot() -> anyhow::Result { let output = Command::new("go").args(["env", "GOROOT"]).output()?; if !output.status.success() { bail!("Failed to find $GOROOT"); From 0535426fd6a3cd9c34932203165f71e1271fc459 Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 12:39:03 +0100 Subject: [PATCH 12/13] fix(example): bump minimum go version due to synctest usage --- example/go.mod | 2 +- go.mod | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/go.mod b/example/go.mod index f148fce1..6ec870e2 100644 --- a/example/go.mod +++ b/example/go.mod @@ -1,6 +1,6 @@ module example -go 1.24.3 +go 1.25 require ( github.com/frankban/quicktest v1.14.6 diff --git a/go.mod b/go.mod index 124f58c2..52f63beb 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/CodSpeedHQ/codspeed-go -go 1.24.3 +go 1.25 From 59c0bdacfdf197061f64700c2aff701e80c4704f Mon Sep 17 00:00:00 2001 From: not-matthias Date: Fri, 9 Jan 2026 12:42:54 +0100 Subject: [PATCH 13/13] fix(go-runner): check Go version compatibility before running tests --- go-runner/src/integration_tests.rs | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/go-runner/src/integration_tests.rs b/go-runner/src/integration_tests.rs index d82d642b..f0e2874f 100644 --- a/go-runner/src/integration_tests.rs +++ b/go-runner/src/integration_tests.rs @@ -3,6 +3,7 @@ use rstest::rstest; use std::path::{Path, PathBuf}; use tempfile::TempDir; +use crate::prelude::*; use crate::results::walltime_results::WalltimeResults; fn assert_results_snapshots(profile_dir: &Path, project_name: &str) { @@ -84,6 +85,14 @@ fn test_build_and_run(#[case] project_name: &str) { .join("testdata/projects") .join(project_name); + if !can_build_project(&project_dir) { + warn!( + "Skipping project {} because it requires a different Go version", + project_name + ); + return; + } + let temp_dir = TempDir::new().unwrap(); let profile_dir = temp_dir.path().join("profile"); let cli = crate::cli::Cli { @@ -96,3 +105,54 @@ fn test_build_and_run(#[case] project_name: &str) { assert_results_snapshots(&profile_dir, project_name); } + +fn can_build_project(project_dir: &Path) -> bool { + if let Some(required_version) = project_go_version(project_dir) { + let current_version = go_version().unwrap(); + info!( + "Project requires Go {}, current version is {}", + required_version, current_version + ); + required_version.matches(¤t_version) + } else { + true + } +} + +fn go_version() -> anyhow::Result { + use anyhow::Context; + + let output = std::process::Command::new("go").arg("version").output()?; + if !output.status.success() { + panic!("Failed to get Go version"); + } + let output = String::from_utf8_lossy(&output.stdout); + + // Example output: go version go1.24.9 linux/amd64 + let go_version_str = output + .split_whitespace() + .nth(2) + .context("Failed to parse Go version")? + .strip_prefix("go") + .context("Failed to strip 'go' prefix")?; + Ok(semver::Version::parse(go_version_str)?) +} + +// Check whether the go.mod expects a specific Go version, and skip the test if not met +fn project_go_version(project_dir: &Path) -> Option { + let go_mod_path = project_dir.join("go.mod"); + if !go_mod_path.exists() { + return None; + } + + let go_mod_content = std::fs::read_to_string(go_mod_path).unwrap_or_default(); + for line in go_mod_content.lines() { + let Some(version_str) = line.strip_prefix("go ") else { + continue; + }; + + return semver::VersionReq::parse(version_str).ok(); + } + + None +}