Skip to content

Commit

Permalink
qsort: add benchmarks from the standard library
Browse files Browse the repository at this point in the history
These will let us be more confident that a custom sort algorithm makes
sense to use, especially when e.g. the Go standard library introduces
a new sorting algorithm, we can compare the two.

On my Mac, using the pdqsort from Go 1.19, the relevant timings are:

    Sort8/100000-10             4.91ms ± 0%
    Sort8/1000000-10            60.1ms ± 0%
    StdlibSort8/100000-10       8.16ms ± 0%
    StdlibSort8/1000000-10       103ms ± 0%

    Sort8/100000-10            163MB/s ± 0%
    Sort8/1000000-10           133MB/s ± 0%
    StdlibSort8/100000-10     98.0MB/s ± 0%
    StdlibSort8/1000000-10    77.5MB/s ± 0%

Compared to the Go 1.18 sort algorithm:

    Sort8/100000-10             4.90ms ± 0%
    Sort8/1000000-10            59.0ms ± 0%
    StdlibSort8/100000-10       8.53ms ± 0%
    StdlibSort8/1000000-10       105ms ± 0%

    Sort8/100000-10            163MB/s ± 0%
    Sort8/1000000-10           136MB/s ± 0%
    StdlibSort8/100000-10     93.8MB/s ± 0%
    StdlibSort8/1000000-10    76.0MB/s ± 0%

So the Go standard library sort performance is improving but we are
still about 40% faster than the benchmark.
  • Loading branch information
kevinburkesegment committed Apr 26, 2022
1 parent 3e23660 commit aee0221
Showing 1 changed file with 31 additions and 1 deletion.
32 changes: 31 additions & 1 deletion qsort/sort_test.go
Expand Up @@ -11,6 +11,9 @@ import (

var prng = rand.New(rand.NewSource(0))

// Note, "8", "16", "32" etc are all byte measurements, not bits. So a 32 byte
// integer, for example, which you might see in e.g. a SHA256 hash.

func TestSort8(t *testing.T) {
testSort(t, 8)
}
Expand Down Expand Up @@ -162,6 +165,31 @@ func BenchmarkSort8(b *testing.B) {
}
}

func stdlibSort8(b *testing.B, size int) {
// 8 bytes per int64
b.SetBytes(8 * int64(size))
data := make([]int64, size)
unsorted := make([]int64, size)
for j := 0; j < len(unsorted); j++ {
unsorted[j] = int64(rand.Intn(size / 10))
}
b.StopTimer()
for i := 0; i < b.N; i++ {
copy(data, unsorted)
b.StartTimer()
sort.Slice(data, func(i, j int) bool { return data[i] < data[j] })
b.StopTimer()
}
}

func BenchmarkStdlibSort8(b *testing.B) {
for _, size := range []int{1e5, 1e6} {
b.Run(strconv.Itoa(size), func(b *testing.B) {
stdlibSort8(b, size)
})
}
}

func BenchmarkSort8Indirect(b *testing.B) {
swap := func(int, int) {}
const count = 100000
Expand Down Expand Up @@ -222,6 +250,7 @@ const (

func benchSort(count, size int, order order, indirect func(int, int)) func(*testing.B) {
return func(b *testing.B) {
b.StopTimer()
buf := make([]byte, count*size)
unsorted := make([]byte, count*size)
prng.Read(unsorted)
Expand All @@ -238,11 +267,12 @@ func benchSort(count, size int, order order, indirect func(int, int)) func(*test
}

b.SetBytes(int64(len(buf)))
b.ResetTimer()

for i := 0; i < b.N; i++ {
copy(buf, unsorted)
b.StartTimer()
Sort(buf, size, indirect)
b.StopTimer()
}
}
}

0 comments on commit aee0221

Please sign in to comment.