Skip to content

Commit c3da3bc

Browse files
committed
sort: forward fixed-type slice sorting to slices package
Forwards the following functions to the slices package: sort.Ints sort.Strings sort.Float64s sort.IntsAreSorted sort.StringsAreSorted sort.Float64sAreSorted benchstat results on the sort package's benchmarks: goos: linux goarch: amd64 pkg: sort cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz SearchWrappers-8 58.10n ± 0% 58.43n ± 1% +0.57% (p=0.004 n=10) SortString1K-8 76.53µ ± 1% 66.04µ ± 2% -13.71% (p=0.000 n=10) SortString1K_Slice-8 71.99µ ± 1% 72.32µ ± 2% ~ (p=0.481 n=10) StableString1K-8 92.66µ ± 1% 92.10µ ± 2% -0.61% (p=0.019 n=10) SortInt1K-8 34.31µ ± 0% 11.49µ ± 2% -66.50% (p=0.000 n=10) SortInt1K_Sorted-8 2699.5n ± 1% 959.0n ± 3% -64.47% (p=0.000 n=10) SortInt1K_Reversed-8 3.990µ ± 1% 1.429µ ± 4% -64.19% (p=0.000 n=10) SortInt1K_Mod8-8 13.695µ ± 1% 5.129µ ± 2% -62.55% (p=0.000 n=10) StableInt1K-8 46.22µ ± 1% 46.80µ ± 1% ~ (p=0.109 n=10) StableInt1K_Slice-8 44.12µ ± 1% 44.32µ ± 2% ~ (p=0.315 n=10) SortInt64K-8 3.848m ± 0% 1.857m ± 2% -51.76% (p=0.000 n=10) SortInt64K_Slice-8 3.690m ± 0% 3.740m ± 0% +1.36% (p=0.002 n=10) StableInt64K-8 3.901m ± 0% 3.917m ± 0% +0.42% (p=0.003 n=10) Sort1e2-8 32.22µ ± 2% 32.40µ ± 2% ~ (p=0.529 n=10) Stable1e2-8 54.11µ ± 1% 54.11µ ± 1% ~ (p=0.796 n=10) Sort1e4-8 5.998m ± 1% 5.993m ± 1% ~ (p=0.579 n=10) Stable1e4-8 15.23m ± 0% 15.32m ± 0% +0.59% (p=0.000 n=10) Sort1e6-8 902.8m ± 0% 904.3m ± 0% ~ (p=0.075 n=10) Stable1e6-8 3.089 ± 0% 3.089 ± 0% ~ (p=0.971 n=10) geomean 259.8µ 200.0µ -22.99% Most of the benchmarks are unaffected. The ones with significant reductions are precisely for the functions that were forwarded. This CL has to move some things around to avoid a circular dependency between sort and slices. Since sort depends on slices now, nothing in slices can depend on sort - not even in tests. Fixes #61180 Change-Id: Ic0e5f519863d96a139fada08aefb1bcdf4c7a9a3 Reviewed-on: https://go-review.googlesource.com/c/go/+/508135 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Eli Bendersky <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 12f3d68 commit c3da3bc

10 files changed

+297
-301
lines changed

src/go/build/deps_test.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,15 @@ var depsRules = `
7777
< internal/oserror, math/bits
7878
< RUNTIME;
7979
80-
RUNTIME
81-
< sort
80+
# slices depends on unsafe for overlapping check, cmp for comparison
81+
# semantics, and math/bits for # calculating bitlength of numbers.
82+
unsafe, cmp, math/bits
83+
< slices;
84+
85+
RUNTIME, slices
86+
< sort;
87+
88+
sort
8289
< container/heap;
8390
8491
RUNTIME
@@ -223,11 +230,6 @@ var depsRules = `
223230
< hash
224231
< hash/adler32, hash/crc32, hash/crc64, hash/fnv;
225232
226-
# slices depends on unsafe for overlapping check, cmp for comparison
227-
# semantics, and math/bits for # calculating bitlength of numbers.
228-
unsafe, cmp, math/bits
229-
< slices;
230-
231233
# math/big
232234
FMT, encoding/binary, math/rand
233235
< math/big;

src/slices/slices_test.go

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package slices
5+
package slices_test
66

77
import (
88
"cmp"
99
"internal/race"
1010
"internal/testenv"
1111
"math"
12+
. "slices"
1213
"strings"
1314
"testing"
1415
)
@@ -999,25 +1000,6 @@ func BenchmarkReplace(b *testing.B) {
9991000

10001001
}
10011002

1002-
func TestRotate(t *testing.T) {
1003-
const N = 10
1004-
s := make([]int, 0, N)
1005-
for n := 0; n < N; n++ {
1006-
for r := 0; r < n; r++ {
1007-
s = s[:0]
1008-
for i := 0; i < n; i++ {
1009-
s = append(s, i)
1010-
}
1011-
rotateLeft(s, r)
1012-
for i := 0; i < n; i++ {
1013-
if s[i] != (i+r)%n {
1014-
t.Errorf("expected n=%d r=%d i:%d want:%d got:%d", n, r, i, (i+r)%n, s[i])
1015-
}
1016-
}
1017-
}
1018-
}
1019-
}
1020-
10211003
func TestInsertGrowthRate(t *testing.T) {
10221004
b := make([]byte, 1)
10231005
maxCap := cap(b)

src/slices/sort_benchmark_test.go

Lines changed: 9 additions & 242 deletions
Original file line numberDiff line numberDiff line change
@@ -2,252 +2,14 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package slices
5+
package slices_test
66

77
import (
88
"fmt"
9-
"math/rand"
10-
"sort"
11-
"strconv"
12-
"strings"
9+
"slices"
1310
"testing"
1411
)
1512

16-
// These benchmarks compare sorting a large slice of int with sort.Ints vs.
17-
// slices.Sort
18-
func makeRandomInts(n int) []int {
19-
rand.Seed(42)
20-
ints := make([]int, n)
21-
for i := 0; i < n; i++ {
22-
ints[i] = rand.Intn(n)
23-
}
24-
return ints
25-
}
26-
27-
func makeSortedInts(n int) []int {
28-
ints := make([]int, n)
29-
for i := 0; i < n; i++ {
30-
ints[i] = i
31-
}
32-
return ints
33-
}
34-
35-
func makeReversedInts(n int) []int {
36-
ints := make([]int, n)
37-
for i := 0; i < n; i++ {
38-
ints[i] = n - i
39-
}
40-
return ints
41-
}
42-
43-
const N = 100_000
44-
45-
func BenchmarkSortInts(b *testing.B) {
46-
for i := 0; i < b.N; i++ {
47-
b.StopTimer()
48-
ints := makeRandomInts(N)
49-
b.StartTimer()
50-
sort.Ints(ints)
51-
}
52-
}
53-
54-
func makeSortedStrings(n int) []string {
55-
x := make([]string, n)
56-
for i := 0; i < n; i++ {
57-
x[i] = strconv.Itoa(i)
58-
}
59-
Sort(x)
60-
return x
61-
}
62-
63-
func BenchmarkSlicesSortInts(b *testing.B) {
64-
for i := 0; i < b.N; i++ {
65-
b.StopTimer()
66-
ints := makeRandomInts(N)
67-
b.StartTimer()
68-
Sort(ints)
69-
}
70-
}
71-
72-
func BenchmarkSlicesSortInts_Sorted(b *testing.B) {
73-
for i := 0; i < b.N; i++ {
74-
b.StopTimer()
75-
ints := makeSortedInts(N)
76-
b.StartTimer()
77-
Sort(ints)
78-
}
79-
}
80-
81-
func BenchmarkSlicesSortInts_Reversed(b *testing.B) {
82-
for i := 0; i < b.N; i++ {
83-
b.StopTimer()
84-
ints := makeReversedInts(N)
85-
b.StartTimer()
86-
Sort(ints)
87-
}
88-
}
89-
90-
func BenchmarkIntsAreSorted(b *testing.B) {
91-
for i := 0; i < b.N; i++ {
92-
b.StopTimer()
93-
ints := makeSortedInts(N)
94-
b.StartTimer()
95-
sort.IntsAreSorted(ints)
96-
}
97-
}
98-
99-
func BenchmarkIsSorted(b *testing.B) {
100-
for i := 0; i < b.N; i++ {
101-
b.StopTimer()
102-
ints := makeSortedInts(N)
103-
b.StartTimer()
104-
IsSorted(ints)
105-
}
106-
}
107-
108-
// Since we're benchmarking these sorts against each other, make sure that they
109-
// generate similar results.
110-
func TestIntSorts(t *testing.T) {
111-
ints := makeRandomInts(200)
112-
ints2 := Clone(ints)
113-
114-
sort.Ints(ints)
115-
Sort(ints2)
116-
117-
for i := range ints {
118-
if ints[i] != ints2[i] {
119-
t.Fatalf("ints2 mismatch at %d; %d != %d", i, ints[i], ints2[i])
120-
}
121-
}
122-
}
123-
124-
// The following is a benchmark for sorting strings.
125-
126-
// makeRandomStrings generates n random strings with alphabetic runes of
127-
// varying lengths.
128-
func makeRandomStrings(n int) []string {
129-
rand.Seed(42)
130-
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
131-
ss := make([]string, n)
132-
for i := 0; i < n; i++ {
133-
var sb strings.Builder
134-
slen := 2 + rand.Intn(50)
135-
for j := 0; j < slen; j++ {
136-
sb.WriteRune(letters[rand.Intn(len(letters))])
137-
}
138-
ss[i] = sb.String()
139-
}
140-
return ss
141-
}
142-
143-
func TestStringSorts(t *testing.T) {
144-
ss := makeRandomStrings(200)
145-
ss2 := Clone(ss)
146-
147-
sort.Strings(ss)
148-
Sort(ss2)
149-
150-
for i := range ss {
151-
if ss[i] != ss2[i] {
152-
t.Fatalf("ss2 mismatch at %d; %s != %s", i, ss[i], ss2[i])
153-
}
154-
}
155-
}
156-
157-
func BenchmarkSortStrings(b *testing.B) {
158-
for i := 0; i < b.N; i++ {
159-
b.StopTimer()
160-
ss := makeRandomStrings(N)
161-
b.StartTimer()
162-
sort.Strings(ss)
163-
}
164-
}
165-
166-
func BenchmarkSortStrings_Sorted(b *testing.B) {
167-
ss := makeSortedStrings(N)
168-
b.ResetTimer()
169-
170-
for i := 0; i < b.N; i++ {
171-
sort.Strings(ss)
172-
}
173-
}
174-
175-
func BenchmarkSlicesSortStrings(b *testing.B) {
176-
for i := 0; i < b.N; i++ {
177-
b.StopTimer()
178-
ss := makeRandomStrings(N)
179-
b.StartTimer()
180-
Sort(ss)
181-
}
182-
}
183-
184-
func BenchmarkSlicesSortStrings_Sorted(b *testing.B) {
185-
ss := makeSortedStrings(N)
186-
b.ResetTimer()
187-
188-
for i := 0; i < b.N; i++ {
189-
Sort(ss)
190-
}
191-
}
192-
193-
// These benchmarks compare sorting a slice of structs with sort.Sort vs.
194-
// slices.SortFunc.
195-
type myStruct struct {
196-
a, b, c, d string
197-
n int
198-
}
199-
200-
type myStructs []*myStruct
201-
202-
func (s myStructs) Len() int { return len(s) }
203-
func (s myStructs) Less(i, j int) bool { return s[i].n < s[j].n }
204-
func (s myStructs) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
205-
206-
func makeRandomStructs(n int) myStructs {
207-
rand.Seed(42)
208-
structs := make([]*myStruct, n)
209-
for i := 0; i < n; i++ {
210-
structs[i] = &myStruct{n: rand.Intn(n)}
211-
}
212-
return structs
213-
}
214-
215-
func TestStructSorts(t *testing.T) {
216-
ss := makeRandomStructs(200)
217-
ss2 := make([]*myStruct, len(ss))
218-
for i := range ss {
219-
ss2[i] = &myStruct{n: ss[i].n}
220-
}
221-
222-
sort.Sort(ss)
223-
SortFunc(ss2, func(a, b *myStruct) int { return a.n - b.n })
224-
225-
for i := range ss {
226-
if *ss[i] != *ss2[i] {
227-
t.Fatalf("ints2 mismatch at %d; %v != %v", i, *ss[i], *ss2[i])
228-
}
229-
}
230-
}
231-
232-
func BenchmarkSortStructs(b *testing.B) {
233-
for i := 0; i < b.N; i++ {
234-
b.StopTimer()
235-
ss := makeRandomStructs(N)
236-
b.StartTimer()
237-
sort.Sort(ss)
238-
}
239-
}
240-
241-
func BenchmarkSortFuncStructs(b *testing.B) {
242-
cmpFunc := func(a, b *myStruct) int { return a.n - b.n }
243-
for i := 0; i < b.N; i++ {
244-
b.StopTimer()
245-
ss := makeRandomStructs(N)
246-
b.StartTimer()
247-
SortFunc(ss, cmpFunc)
248-
}
249-
}
250-
25113
func BenchmarkBinarySearchFloats(b *testing.B) {
25214
for _, size := range []int{16, 32, 64, 128, 512, 1024} {
25315
b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
@@ -259,12 +21,17 @@ func BenchmarkBinarySearchFloats(b *testing.B) {
25921
needle := (floats[midpoint] + floats[midpoint+1]) / 2
26022
b.ResetTimer()
26123
for i := 0; i < b.N; i++ {
262-
BinarySearch(floats, needle)
24+
slices.BinarySearch(floats, needle)
26325
}
26426
})
26527
}
26628
}
26729

30+
type myStruct struct {
31+
a, b, c, d string
32+
n int
33+
}
34+
26835
func BenchmarkBinarySearchFuncStruct(b *testing.B) {
26936
for _, size := range []int{16, 32, 64, 128, 512, 1024} {
27037
b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) {
@@ -277,7 +44,7 @@ func BenchmarkBinarySearchFuncStruct(b *testing.B) {
27744
lessFunc := func(a, b *myStruct) int { return a.n - b.n }
27845
b.ResetTimer()
27946
for i := 0; i < b.N; i++ {
280-
BinarySearchFunc(structs, needle, lessFunc)
47+
slices.BinarySearchFunc(structs, needle, lessFunc)
28148
}
28249
})
28350
}

0 commit comments

Comments
 (0)