Skip to content

Commit 47ecfdc

Browse files
egonelbregopherbot
authored andcommitted
slices: optimize Index and Compact for large types
Using `for i, v := range` loops causes extra copies. Try to get rid of as much copies as possible. │ old.txt~ │ new.txt~ │ │ sec/op │ sec/op vs base │ EqualFunc_Large-32 1.077m ± 1% 1.072m ± 1% ~ (p=0.631 n=10) Index_Large-32 346.329µ ± 1% 6.510µ ± 24% -98.12% (p=0.000 n=10) IndexFunc_Large-32 502.9µ ± 0% 381.2µ ± 1% -24.21% (p=0.000 n=10) Compact_Large-32 409.5µ ± 1% 145.2µ ± 9% -64.54% (p=0.000 n=10) CompactFunc_Large-32 693.5µ ± 1% 663.1µ ± 3% -4.39% (p=0.000 n=10) geomean 556.3µ 191.3µ -65.61% Change-Id: I187065ea32394b241951928bada7a698a9f45cd9 Reviewed-on: https://go-review.googlesource.com/c/exp/+/486735 Auto-Submit: Ian Lance Taylor <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 0ee363d commit 47ecfdc

File tree

2 files changed

+61
-14
lines changed

2 files changed

+61
-14
lines changed

slices/slices.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@ func CompareFunc[E1, E2 any](s1 []E1, s2 []E2, cmp func(E1, E2) int) int {
104104
// Index returns the index of the first occurrence of v in s,
105105
// or -1 if not present.
106106
func Index[E comparable](s []E, v E) int {
107-
for i, vs := range s {
108-
if v == vs {
107+
for i := range s {
108+
if v == s[i] {
109109
return i
110110
}
111111
}
@@ -115,8 +115,8 @@ func Index[E comparable](s []E, v E) int {
115115
// IndexFunc returns the first index i satisfying f(s[i]),
116116
// or -1 if none do.
117117
func IndexFunc[E any](s []E, f func(E) bool) int {
118-
for i, v := range s {
119-
if f(v) {
118+
for i := range s {
119+
if f(s[i]) {
120120
return i
121121
}
122122
}
@@ -207,12 +207,12 @@ func Compact[S ~[]E, E comparable](s S) S {
207207
return s
208208
}
209209
i := 1
210-
last := s[0]
211-
for _, v := range s[1:] {
212-
if v != last {
213-
s[i] = v
210+
for k := 1; k < len(s); k++ {
211+
if s[k] != s[k-1] {
212+
if i != k {
213+
s[i] = s[k]
214+
}
214215
i++
215-
last = v
216216
}
217217
}
218218
return s[:i]
@@ -224,12 +224,12 @@ func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
224224
return s
225225
}
226226
i := 1
227-
last := s[0]
228-
for _, v := range s[1:] {
229-
if !eq(v, last) {
230-
s[i] = v
227+
for k := 1; k < len(s); k++ {
228+
if !eq(s[k], s[k-1]) {
229+
if i != k {
230+
s[i] = s[k]
231+
}
231232
i++
232-
last = v
233233
}
234234
}
235235
return s[:i]

slices/slices_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ func TestEqualFunc(t *testing.T) {
126126
}
127127
}
128128

129+
func BenchmarkEqualFunc_Large(b *testing.B) {
130+
type Large [4 * 1024]byte
131+
132+
xs := make([]Large, 1024)
133+
ys := make([]Large, 1024)
134+
for i := 0; i < b.N; i++ {
135+
_ = EqualFunc(xs, ys, func(x, y Large) bool { return x == y })
136+
}
137+
}
138+
129139
var compareIntTests = []struct {
130140
s1, s2 []int
131141
want int
@@ -334,6 +344,15 @@ func equalToIndex[T any](f func(T, T) bool, v1 T) func(T) bool {
334344
}
335345
}
336346

347+
func BenchmarkIndex_Large(b *testing.B) {
348+
type Large [4 * 1024]byte
349+
350+
ss := make([]Large, 1024)
351+
for i := 0; i < b.N; i++ {
352+
_ = Index(ss, Large{1})
353+
}
354+
}
355+
337356
func TestIndexFunc(t *testing.T) {
338357
for _, test := range indexTests {
339358
if got := IndexFunc(test.s, equalToIndex(equal[int], test.v)); got != test.want {
@@ -350,6 +369,17 @@ func TestIndexFunc(t *testing.T) {
350369
}
351370
}
352371

372+
func BenchmarkIndexFunc_Large(b *testing.B) {
373+
type Large [4 * 1024]byte
374+
375+
ss := make([]Large, 1024)
376+
for i := 0; i < b.N; i++ {
377+
_ = IndexFunc(ss, func(e Large) bool {
378+
return e == Large{1}
379+
})
380+
}
381+
}
382+
353383
func TestContains(t *testing.T) {
354384
for _, test := range indexTests {
355385
if got := Contains(test.s, test.v); got != (test.want != -1) {
@@ -572,7 +602,15 @@ func BenchmarkCompact(b *testing.B) {
572602
}
573603
})
574604
}
605+
}
606+
607+
func BenchmarkCompact_Large(b *testing.B) {
608+
type Large [4 * 1024]byte
575609

610+
ss := make([]Large, 1024)
611+
for i := 0; i < b.N; i++ {
612+
_ = Compact(ss)
613+
}
576614
}
577615

578616
func TestCompactFunc(t *testing.T) {
@@ -591,6 +629,15 @@ func TestCompactFunc(t *testing.T) {
591629
}
592630
}
593631

632+
func BenchmarkCompactFunc_Large(b *testing.B) {
633+
type Large [4 * 1024]byte
634+
635+
ss := make([]Large, 1024)
636+
for i := 0; i < b.N; i++ {
637+
_ = CompactFunc(ss, func(a, b Large) bool { return a == b })
638+
}
639+
}
640+
594641
func TestGrow(t *testing.T) {
595642
s1 := []int{1, 2, 3}
596643

0 commit comments

Comments
 (0)