Skip to content

Commit d9464de

Browse files
authored
perf: improve pool performance for pointer types (#147)
1 parent f1e519f commit d9464de

File tree

4 files changed

+37
-61
lines changed

4 files changed

+37
-61
lines changed

nilcheck.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
package don
22

3-
import (
4-
"reflect"
5-
"unsafe"
6-
)
3+
import "reflect"
74

85
func newNilCheck(zero any) func(v any) bool {
96
typ := reflect.TypeOf(zero)
@@ -19,22 +16,12 @@ func newNilCheck(zero any) func(v any) bool {
1916
return func(v any) bool { return v == zero }
2017
case reflect.Map:
2118
// Return true for and nil map.
22-
return func(v any) bool {
23-
return (*emptyInterface)(unsafe.Pointer(&v)).ptr == nil
24-
}
19+
return func(v any) bool { return dataOf(v) == nil }
2520
case reflect.Slice:
2621
// Return true for nil slice.
27-
return func(v any) bool {
28-
return (*reflect.SliceHeader)((*emptyInterface)(unsafe.Pointer(&v)).ptr).Data == 0
29-
}
22+
return func(v any) bool { return (*reflect.SliceHeader)(dataOf(v)).Data == 0 }
3023
default:
3124
// Return false for all others.
3225
return func(v any) bool { return false }
3326
}
3427
}
35-
36-
// emptyInterface is the header for an interface{} value.
37-
type emptyInterface struct {
38-
typ unsafe.Pointer
39-
ptr unsafe.Pointer
40-
}

pool.go

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@ type pool[T any] interface {
1010
Put(*T)
1111
}
1212

13-
type resetter interface {
14-
Reset()
15-
}
16-
17-
var resetterType = reflect.TypeOf((*resetter)(nil)).Elem()
18-
1913
type requestPool[T any] struct {
2014
pool sync.Pool
2115
reset func(*T)
@@ -37,21 +31,17 @@ func newRequestPool[T any](zero T) pool[T] {
3731
*v = zero
3832
}
3933
} else {
34+
rtype := dataOf(typ)
4035
elem := typ.Elem()
36+
elemrtype := dataOf(elem)
37+
zero := dataOf(reflect.New(elem).Elem().Interface())
38+
4139
p.pool.New = func() any {
42-
v := reflect.New(elem).Interface().(T) //nolint:forcetypeassert
40+
v := packEface(rtype, unsafe_New(elemrtype)).(T) //nolint:forcetypeassert
4341
return &v
4442
}
45-
46-
if typ.Implements(resetterType) {
47-
p.reset = func(v *T) {
48-
any(*v).(resetter).Reset() //nolint:forcetypeassert
49-
}
50-
} else {
51-
zeroValue := reflect.New(elem).Elem()
52-
p.reset = func(v *T) {
53-
reflect.ValueOf(v).Elem().Elem().Set(zeroValue)
54-
}
43+
p.reset = func(v *T) {
44+
typedmemmove(elemrtype, dataOf(*v), zero)
5545
}
5646
}
5747

pool_test.go

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -60,32 +60,4 @@ func TestRequestPool(t *testing.T) {
6060
}
6161
}
6262
})
63-
64-
t.Run("Resetter", func(t *testing.T) {
65-
zero := &itemResetter{}
66-
pool := don.NewRequestPool(zero)
67-
68-
for i := 0; i < 100; i++ {
69-
p := pool.Get()
70-
v := *p
71-
v.String = "test"
72-
v.Pointer = &v.String
73-
pool.Put(p)
74-
}
75-
76-
for i := 0; i < 100; i++ {
77-
if !reflect.DeepEqual(&zero, pool.Get()) {
78-
t.Fatal("should be zero value")
79-
}
80-
}
81-
})
82-
}
83-
84-
type itemResetter struct {
85-
String string
86-
Pointer *string
87-
}
88-
89-
func (ir *itemResetter) Reset() {
90-
*ir = itemResetter{}
9163
}

unsafe.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package don
2+
3+
import "unsafe"
4+
5+
//go:linkname unsafe_New reflect.unsafe_New
6+
func unsafe_New(unsafe.Pointer) unsafe.Pointer //nolint:revive
7+
8+
//go:linkname typedmemmove reflect.typedmemmove
9+
func typedmemmove(t, dst, src unsafe.Pointer)
10+
11+
// emptyInterface is the header for an interface{} value.
12+
type emptyInterface struct {
13+
typ unsafe.Pointer
14+
ptr unsafe.Pointer
15+
}
16+
17+
func dataOf(v any) unsafe.Pointer {
18+
return (*emptyInterface)(unsafe.Pointer(&v)).ptr
19+
}
20+
21+
func packEface(typ, ptr unsafe.Pointer) any {
22+
var i any
23+
e := (*emptyInterface)(unsafe.Pointer(&i))
24+
e.typ = typ
25+
e.ptr = ptr
26+
return i
27+
}

0 commit comments

Comments
 (0)