github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/base/bslice/sort_benchmark_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bslice 6 7 import ( 8 "fmt" 9 "math/rand" 10 "sort" 11 "strings" 12 "testing" 13 ) 14 15 // These benchmarks compare sorting a large slice of int with sort.Ints vs. 16 // slices.Sort 17 func makeRandomInts(n int) []int { 18 rand.Seed(42) 19 ints := make([]int, n) 20 for i := 0; i < n; i++ { 21 ints[i] = rand.Intn(n) 22 } 23 return ints 24 } 25 26 func makeSortedInts(n int) []int { 27 ints := make([]int, n) 28 for i := 0; i < n; i++ { 29 ints[i] = i 30 } 31 return ints 32 } 33 34 func makeReversedInts(n int) []int { 35 ints := make([]int, n) 36 for i := 0; i < n; i++ { 37 ints[i] = n - i 38 } 39 return ints 40 } 41 42 const N = 100_000 43 44 func BenchmarkSortInts(b *testing.B) { 45 for i := 0; i < b.N; i++ { 46 b.StopTimer() 47 ints := makeRandomInts(N) 48 b.StartTimer() 49 sort.Ints(ints) 50 } 51 } 52 53 func BenchmarkSlicesSortInts(b *testing.B) { 54 for i := 0; i < b.N; i++ { 55 b.StopTimer() 56 ints := makeRandomInts(N) 57 b.StartTimer() 58 Sort(ints) 59 } 60 } 61 62 func BenchmarkSlicesSortInts_Sorted(b *testing.B) { 63 for i := 0; i < b.N; i++ { 64 b.StopTimer() 65 ints := makeSortedInts(N) 66 b.StartTimer() 67 Sort(ints) 68 } 69 } 70 71 func BenchmarkSlicesSortInts_Reversed(b *testing.B) { 72 for i := 0; i < b.N; i++ { 73 b.StopTimer() 74 ints := makeReversedInts(N) 75 b.StartTimer() 76 Sort(ints) 77 } 78 } 79 80 // Since we're benchmarking these sorts against each other, make sure that they 81 // generate similar results. 82 func TestIntSorts(t *testing.T) { 83 ints := makeRandomInts(200) 84 ints2 := Clone(ints) 85 86 sort.Ints(ints) 87 Sort(ints2) 88 89 for i := range ints { 90 if ints[i] != ints2[i] { 91 t.Fatalf("ints2 mismatch at %d; %d != %d", i, ints[i], ints2[i]) 92 } 93 } 94 } 95 96 // The following is a benchmark for sorting strings. 97 98 // makeRandomStrings generates n random strings with alphabetic runes of 99 // varying lenghts. 100 func makeRandomStrings(n int) []string { 101 rand.Seed(42) 102 var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 103 ss := make([]string, n) 104 for i := 0; i < n; i++ { 105 var sb strings.Builder 106 slen := 2 + rand.Intn(50) 107 for j := 0; j < slen; j++ { 108 sb.WriteRune(letters[rand.Intn(len(letters))]) 109 } 110 ss[i] = sb.String() 111 } 112 return ss 113 } 114 115 func TestStringSorts(t *testing.T) { 116 ss := makeRandomStrings(200) 117 ss2 := Clone(ss) 118 119 sort.Strings(ss) 120 Sort(ss2) 121 122 for i := range ss { 123 if ss[i] != ss2[i] { 124 t.Fatalf("ss2 mismatch at %d; %s != %s", i, ss[i], ss2[i]) 125 } 126 } 127 } 128 129 func BenchmarkSortStrings(b *testing.B) { 130 for i := 0; i < b.N; i++ { 131 b.StopTimer() 132 ss := makeRandomStrings(N) 133 b.StartTimer() 134 sort.Strings(ss) 135 } 136 } 137 138 func BenchmarkSlicesSortStrings(b *testing.B) { 139 for i := 0; i < b.N; i++ { 140 b.StopTimer() 141 ss := makeRandomStrings(N) 142 b.StartTimer() 143 Sort(ss) 144 } 145 } 146 147 // These benchmarks compare sorting a slice of structs with sort.Sort vs. 148 // slices.SortFunc. 149 type myStruct struct { 150 a, b, c, d string 151 n int 152 } 153 154 type myStructs []*myStruct 155 156 func (s myStructs) Len() int { return len(s) } 157 func (s myStructs) Less(i, j int) bool { return s[i].n < s[j].n } 158 func (s myStructs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 159 160 func makeRandomStructs(n int) myStructs { 161 rand.Seed(42) 162 structs := make([]*myStruct, n) 163 for i := 0; i < n; i++ { 164 structs[i] = &myStruct{n: rand.Intn(n)} 165 } 166 return structs 167 } 168 169 func TestStructSorts(t *testing.T) { 170 ss := makeRandomStructs(200) 171 ss2 := make([]*myStruct, len(ss)) 172 for i := range ss { 173 ss2[i] = &myStruct{n: ss[i].n} 174 } 175 176 sort.Sort(ss) 177 SortFunc(ss2, func(a, b *myStruct) bool { return a.n < b.n }) 178 179 for i := range ss { 180 if *ss[i] != *ss2[i] { 181 t.Fatalf("ints2 mismatch at %d; %v != %v", i, *ss[i], *ss2[i]) 182 } 183 } 184 } 185 186 func BenchmarkSortStructs(b *testing.B) { 187 for i := 0; i < b.N; i++ { 188 b.StopTimer() 189 ss := makeRandomStructs(N) 190 b.StartTimer() 191 sort.Sort(ss) 192 } 193 } 194 195 func BenchmarkSortFuncStructs(b *testing.B) { 196 lessFunc := func(a, b *myStruct) bool { return a.n < b.n } 197 for i := 0; i < b.N; i++ { 198 b.StopTimer() 199 ss := makeRandomStructs(N) 200 b.StartTimer() 201 SortFunc(ss, lessFunc) 202 } 203 } 204 205 func BenchmarkBinarySearchFloats(b *testing.B) { 206 for _, size := range []int{16, 32, 64, 128, 512, 1024} { 207 b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) { 208 floats := make([]float64, size) 209 for i := range floats { 210 floats[i] = float64(i) 211 } 212 midpoint := len(floats) / 2 213 needle := (floats[midpoint] + floats[midpoint+1]) / 2 214 b.ResetTimer() 215 for i := 0; i < b.N; i++ { 216 BinarySearch(floats, needle) 217 } 218 }) 219 } 220 } 221 222 func BenchmarkBinarySearchFuncStruct(b *testing.B) { 223 for _, size := range []int{16, 32, 64, 128, 512, 1024} { 224 b.Run(fmt.Sprintf("Size%d", size), func(b *testing.B) { 225 structs := make([]*myStruct, size) 226 for i := range structs { 227 structs[i] = &myStruct{n: i} 228 } 229 midpoint := len(structs) / 2 230 needle := &myStruct{n: (structs[midpoint].n + structs[midpoint+1].n) / 2} 231 lessFunc := func(a, b *myStruct) int { return a.n - b.n } 232 b.ResetTimer() 233 for i := 0; i < b.N; i++ { 234 BinarySearchFunc(structs, needle, lessFunc) 235 } 236 }) 237 } 238 }