Skip to content

Commit

Permalink
Add sorted slice vs heap test
Browse files Browse the repository at this point in the history
  • Loading branch information
prashantv committed Sep 10, 2023
1 parent 965a5eb commit 6c95163
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
22 changes: 22 additions & 0 deletions sorted_vs_heap/bench.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
goos: linux
goarch: amd64
pkg: github.com/prashantv/go-bench/sorted_vs_heap
cpu: 13th Gen Intel(R) Core(TM) i5-13600KF
BenchmarkSorted/1_shuffled_elems 34914072 35.70 ns/op
BenchmarkSorted/1_sorted_elems 32636758 36.06 ns/op
BenchmarkSorted/10_shuffled_elems 2861283 417.3 ns/op
BenchmarkSorted/10_sorted_elems 3316832 360.2 ns/op
BenchmarkSorted/100_shuffled_elems 48640 24599 ns/op
BenchmarkSorted/100_sorted_elems 102871 11621 ns/op
BenchmarkSorted/1000_shuffled_elems 909 1315247 ns/op
BenchmarkSorted/1000_sorted_elems 1603 746310 ns/op
BenchmarkHeap/1_shuffled_elems 97103852 12.06 ns/op
BenchmarkHeap/1_sorted_elems 96106923 12.42 ns/op
BenchmarkHeap/10_shuffled_elems 6392421 188.5 ns/op
BenchmarkHeap/10_sorted_elems 6908209 173.0 ns/op
BenchmarkHeap/100_shuffled_elems 385483 3120 ns/op
BenchmarkHeap/100_sorted_elems 420507 2816 ns/op
BenchmarkHeap/1000_shuffled_elems 14010 85408 ns/op
BenchmarkHeap/1000_sorted_elems 16514 72562 ns/op
PASS
ok github.com/prashantv/go-bench/sorted_vs_heap 22.644s
11 changes: 11 additions & 0 deletions sorted_vs_heap/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module github.com/prashantv/go-bench/sorted_vs_heap

go 1.21.1

require github.com/stretchr/testify v1.8.4

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
10 changes: 10 additions & 0 deletions sorted_vs_heap/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
155 changes: 155 additions & 0 deletions sorted_vs_heap/sorted_vs_heap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package main

import (
"container/heap"
"fmt"
"math/rand"
"sort"
"testing"

"github.com/stretchr/testify/assert"
)

type sortedSlice []int

func newSortedSlice() *sortedSlice { return &sortedSlice{} }
func (ss sortedSlice) Len() int { return len(ss) }
func (ss sortedSlice) Less(i, j int) bool { return ss[i] < ss[j] }
func (ss sortedSlice) Swap(i, j int) { ss[i], ss[j] = ss[j], ss[i] }

func (ss *sortedSlice) PushV(v int) {
*ss = append(*ss, v)
sort.Sort(*ss)
}

func (ss *sortedSlice) PopV() int {
v := (*ss)[0]
*ss = (*ss)[1:]
return v
}

type heapSlice []int

func newHeapSlice() *heapSlice { return &heapSlice{} }
func (h heapSlice) Len() int { return len(h) }
func (h heapSlice) Less(i, j int) bool { return h[i] < h[j] }
func (h heapSlice) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

func (h *heapSlice) Push(v any) {
*h = append(*h, v.(int))
}

func (h *heapSlice) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}

func (h *heapSlice) PushV(v int) {
heap.Push(h, v)
}

func (h *heapSlice) PopV() int {
return heap.Pop(h).(int)
}

type Stack interface {
PushV(v int)
PopV() int
Len() int
}

func BenchmarkSorted(b *testing.B) {
runBenchmarks[*sortedSlice](b, newSortedSlice)
}

func TestSorted(t *testing.T) {
runTests[*sortedSlice](t, newSortedSlice)
}
func BenchmarkHeap(b *testing.B) {
runBenchmarks[*heapSlice](b, newHeapSlice)
}

func TestHeap(t *testing.T) {
runTests[*heapSlice](t, newHeapSlice)
}

func runBenchmarks[S Stack](b *testing.B, newFn func() S) {
for _, numElems := range []int{1, 10, 100, 1000} {
elems := randElems(numElems)
b.Run(fmt.Sprintf("%v shuffled elems", numElems), func(b *testing.B) {
s := newFn()
for i := 0; i < b.N; i++ {
for _, v := range elems {
s.PushV(v)
}
for range elems {
s.PopV()
}
}
})

b.Run(fmt.Sprintf("%v sorted elems", numElems), func(b *testing.B) {
s := newFn()
for i := 0; i < b.N; i++ {
for j := 0; j < numElems; j++ {
s.PushV(j)
}
for j := 0; j < numElems; j++ {
s.PopV()
}
}
})
}
}

func runTests[S Stack](t *testing.T, newFn func() S) {
t.Run("single element", func(t *testing.T) {
s := newFn()
for i := 0; i < 100; i++ {
s.PushV(i)
assert.Equal(t, 1, s.Len())
assert.Equal(t, i, s.PopV())
assert.Equal(t, 0, s.Len())
}
})

t.Run("multiple push/pop", func(t *testing.T) {
push := []int{10, 5, 6, 3, 2, 8, 4, 9, 7, 1, 0}
s := newFn()
for _, v := range push {
s.PushV(v)
}

// Pop some elements
for i := 0; i < 5; i++ {
assert.Equal(t, i, s.PopV())
}

// Then push them back
for i := 0; i < 5; i++ {
s.PushV(4 - i)
}

// Push all
for i := 0; i < 10; i++ {
assert.Equal(t, i, s.PopV())
}
})
}

func randElems(n int) []int {
// Deterministic element ordering
r := rand.New(rand.NewSource(1))

var elems []int
for i := 0; i < n; i++ {
elems = append(elems, i)
}
r.Shuffle(len(elems), func(i, j int) {
elems[i], elems[j] = elems[j], elems[i]
})
return elems
}

0 comments on commit 6c95163

Please sign in to comment.