Skip to content

Commit

Permalink
reflect: optimize TypeFor for non-interface types
Browse files Browse the repository at this point in the history
The reflect.Type.Elem method is somewhat slow,
which is unfortunate since the reflect.TypeOf((*T)(nil)).Elem()
trick is only needed if T is an interface.

Optimize for concrete types by doing the faster reflect.TypeOf(v)
call first and only falling back on the Elem method if needed.

Performance:

	name              old time/op  new time/op  delta
	TypeForString-24  9.10ns ± 1%  1.78ns ± 2%  -80.49%  (p=0.000 n=10+10)
	TypeForError-24   9.55ns ± 1%  9.78ns ± 1%   +2.39%  (p=0.000 n=10+9)

Updates #60088

Change-Id: I2ae76988c9a3dbcbae10d2c19b55db3c8d4559bf
Reviewed-on: https://go-review.googlesource.com/c/go/+/555597
Auto-Submit: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Run-TryBot: Joseph Tsai <joetsai@digital-static.net>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
  • Loading branch information
dsnet authored and gopherbot committed Feb 12, 2024
1 parent 2b58355 commit 2413629
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/reflect/type.go
Expand Up @@ -2920,5 +2920,9 @@ func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) {

// TypeFor returns the [Type] that represents the type argument T.
func TypeFor[T any]() Type {
return TypeOf((*T)(nil)).Elem()
var v T
if t := TypeOf(v); t != nil {
return t // optimize for T being a non-interface kind
}
return TypeOf((*T)(nil)).Elem() // only for an interface kind
}
14 changes: 14 additions & 0 deletions src/reflect/type_test.go
Expand Up @@ -103,3 +103,17 @@ func TestIsRegularMemory(t *testing.T) {
})
}
}

var sinkType reflect.Type

func BenchmarkTypeForString(b *testing.B) {
for i := 0; i < b.N; i++ {
sinkType = reflect.TypeFor[string]()
}
}

func BenchmarkTypeForError(b *testing.B) {
for i := 0; i < b.N; i++ {
sinkType = reflect.TypeFor[error]()
}
}

0 comments on commit 2413629

Please sign in to comment.