Skip to content

Even faster C.Run by using no reflect at all in common cases #165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

dolmen
Copy link
Contributor

@dolmen dolmen commented Aug 1, 2023

In C.Run bypass check of the signature of the Run method of c.TB for the common cases (testing.T.Run, testing.B.Run, quicktest.C.Run) by using a type switch.

Note: this is an alternative version of #160 and replaces it. The first 2 commits are common.

This serie of patches shows the developement process:

  • refactor C.Run to extract getRunFuncSignature
  • add unit test for getRunFuncSignature
  • refactor C.Run to add shortcuts for common cases using a type switch

rogpeppe added a commit to rogpeppe-contrib/quicktest that referenced this pull request Aug 1, 2023
This is an alternative to PRs frankban#160 and frankban#165.
It's essentially the same as PR frankban#165 except that it uses
generics to reduce the amount of duplicated code.

Instead of just amortizing the checking of the type, when
the argument type of the function passed to `Run` is known,
it bypasses the reflect-based code altogether.
We don't bother implementing the optimization on pre-generics
Go versions because those are end-of-lifetime anyway.

I've added an implementation-independent benchmark.

```
goos: linux
goarch: amd64
pkg: github.com/frankban/quicktest
cpu: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
                           │      base      │               thisPR               │
                           │     sec/op     │   sec/op     vs base               │
CNewAndRunWithCustomType-8    1077.5n ±  5%   136.8n ± 6%  -87.30% (p=0.002 n=6)
CRunWithCustomType-8         1035.00n ± 11%   66.43n ± 3%  -93.58% (p=0.002 n=6)
geomean                        1.056µ         95.33n       -90.97%
```
rogpeppe added a commit to rogpeppe-contrib/quicktest that referenced this pull request Aug 1, 2023
This is an alternative to PRs frankban#160 and frankban#165.
It's essentially the same as PR frankban#165 except that it uses
generics to reduce the amount of duplicated code.

Instead of just amortizing the checking of the type, when
the argument type of the function passed to `Run` is known,
it bypasses the reflect-based code altogether.
We don't bother implementing the optimization on pre-generics
Go versions because those are end-of-lifetime anyway.

I've added an implementation-independent benchmark.

```
goos: linux
goarch: amd64
pkg: github.com/frankban/quicktest
cpu: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
                           │      base      │               thisPR               │
                           │     sec/op     │   sec/op     vs base               │
CNewAndRunWithCustomType-8    1077.5n ±  5%   136.8n ± 6%  -87.30% (p=0.002 n=6)
CRunWithCustomType-8         1035.00n ± 11%   66.43n ± 3%  -93.58% (p=0.002 n=6)
geomean                        1.056µ         95.33n       -90.97%
```
@dolmen
Copy link
Contributor Author

dolmen commented Aug 1, 2023

I have just added a commit that factorizes the qt.C setup for both the reflect version and the shortcuts ones. This removes the duplicated code that #166 is partially factorizing using generics.

(*customT)(nil), // a custom form of testing.TB with a non-standard Run method
} {
tbt := reflect.TypeOf(tb)
farg, err := qt.GetRunFuncSignature(tbt)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test isn't great IMHO. Firstly, it tests GetRunFuncSignature which is an internal implementation detail (this module in general tries to test the public API as much as possible to allow later internal refactoring without changing tests). Secondly, GetRunFuncSignature won't even be invoked in most of the above cases, so I'm not sure why this is explicitly testing them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I had written that test in the context of #160, but it isn't relevant anymore here.

Also, the extended tests and benchmarks you wrote in #166 would be welcome on a separate MR (written without generics) and I would be glad to rebase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now removed the commit that added that test.

dolmen added 3 commits August 8, 2023 10:31
Extract signature check of the Run method.
In C.Run add shortcuts to completely bypass the use of reflect for the
well known cases of Run signatures with either *testing.T, *testing.B or
*quicktest.C argument.
Factorize the setup of the qt.C given to the subtest. That setup is now
common to the reflect version and the shortcut ones instead of being
duplicated.
@dolmen
Copy link
Contributor Author

dolmen commented Aug 8, 2023

I've cleaned the PR:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants