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  }