Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: test and benchmarks #5

Merged
merged 1 commit into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
go-version: '1.20'
- name: Run Test
run: make test
- name: Run Benchmark
run: make bench
report:
needs: build
runs-on: ubuntu-latest
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ all: test

.PHONY: test
test:
go clean -testcache
go test -v ./... -cover

.PHONY: bench
bench:
go clean -testcache
go test -v ./... -tags bench

.PHONY: report
report:
go test ./... -coverprofile=./cover.out
Expand Down
88 changes: 88 additions & 0 deletions gomapllrb_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//go:build bench

package gomapllrb

import (
"fmt"
"testing"
"time"

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

func TestBenchmarkRandom(t *testing.T) {
title("Test perfmance / random")
num := 1000000
keys := make([]uint32, num, num)
for i := 0; i < num; i++ {
keys[i] = hash32(i)
}
perfTest(t, keys)
}

func TestBenchmarkAscending(t *testing.T) {
title("Test perfmance / ascending")
num := 1000000
keys := make([]uint32, num, num)
for i := 0; i < num; i++ {
keys[i] = uint32(i)
}
perfTest(t, keys)
}

func perfTest(t *testing.T, keys []uint32) {
assert := assert.New(t)
tree := New[uint32]()

// print key samples
fmt.Printf(" Sample")
for i, k := range keys {
fmt.Printf(" %v", k)
if i == 9 {
break
}
}
fmt.Printf(", ... (Total %d)\n", len(keys))

// put
start := time.Now()
for i, k := range keys {
tree.Put(k, nil)
if VERBOSE && i == 50 {
assertTreeCheck(t, tree, true)
}
}
stats := tree.Stats()
fmt.Printf(" Put %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)
assert.Less(0, tree.Len())
assertTreeCheck(t, tree, false)

// find
tree.ResetStats()
start = time.Now()
for _, k := range keys {
tree.Exist(k)
}
stats = tree.Stats()
fmt.Printf(" Find %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)

// iterator
tree.ResetStats()
start = time.Now()
for it := tree.Iter(); it.Next(); {
// let it loop
}
stats = tree.Stats()
fmt.Printf(" Iter %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)

// delete
tree.ResetStats()
start = time.Now()
for _, k := range keys {
tree.Delete(k)
}
stats = tree.Stats()
fmt.Printf(" Delete %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)
assert.Equal(0, tree.Len())
assertTreeCheck(t, tree, false)
}
46 changes: 46 additions & 0 deletions gomapllrb_helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package gomapllrb

import (
"encoding/binary"
"fmt"
"log"
"testing"

"github.com/spaolacci/murmur3"
"golang.org/x/exp/constraints"
)

const (
VERBOSE = false // enable visual inspections
)

func title(str string) {
fmt.Printf("* TEST : %s\n", str)
}

func hash32(num int) uint32 {
numBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(numBytes, uint32(num))
hash := murmur3.New32()
hash.Write(numBytes)
return hash.Sum32()
}

func assertTreeCheck[K constraints.Ordered](t interface{}, tree *Tree[K], verbose bool) {
if err := tree.Check(); err != nil {
switch t.(type) {
case *testing.T:
t.(*testing.T).Error(err)
case *testing.B:
t.(*testing.B).Error(err)
default:
panic(err)
}
log.Println("ERROR:", err)
verbose = true
}
if verbose {
fmt.Print(tree)
fmt.Printf("(#nodes %d, #red %d, #black %d\n", tree.Len(), 0, 0)
}
}
116 changes: 2 additions & 114 deletions gomapllrb_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
//go:build !bench

package gomapllrb

import (
"encoding/binary"
"fmt"
"log"
"testing"
"time"

"github.com/spaolacci/murmur3"
"github.com/stretchr/testify/assert"
"golang.org/x/exp/constraints"
)

const (
VERBOSE = false // enable visual inspections
)

// Test growth of tree
Expand Down Expand Up @@ -342,108 +335,3 @@ func TestCheck(t *testing.T) {
tree.root.left.left = n
assert.NoError(tree.Check())
}

func TestPerformanceRandom(t *testing.T) {
title("Test perfmance / random")
num := 1000000
keys := make([]uint32, num, num)
for i := 0; i < num; i++ {
keys[i] = hash32(i)
}
perfTest(t, keys)
}

func TestPerformanceAscending(t *testing.T) {
title("Test perfmance / ascending")
num := 1000000
keys := make([]uint32, num, num)
for i := 0; i < num; i++ {
keys[i] = uint32(i)
}
perfTest(t, keys)
}

/*************************************************************************
* Helpers
************************************************************************/

func title(str string) {
fmt.Printf("* TEST : %s\n", str)
}

func assertTreeCheck[K constraints.Ordered](t *testing.T, tree *Tree[K], verbose bool) {
if err := tree.Check(); err != nil {
t.Error(err)
log.Println("ERROR:", err)
verbose = true
}
if verbose {
fmt.Print(tree)
fmt.Printf("(#nodes %d, #red %d, #black %d\n", tree.Len(), 0, 0)
}
}

func hash32(num int) uint32 {
numBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(numBytes, uint32(num))
hash := murmur3.New32()
hash.Write(numBytes)
return hash.Sum32()
}

func perfTest(t *testing.T, keys []uint32) {
assert := assert.New(t)
tree := New[uint32]()

// print key samples
fmt.Printf(" Sample")
for i, k := range keys {
fmt.Printf(" %v", k)
if i == 9 {
break
}
}
fmt.Printf(", ... (Total %d)\n", len(keys))

// put
start := time.Now()
for i, k := range keys {
tree.Put(k, nil)
if VERBOSE && i == 50 {
assertTreeCheck(t, tree, true)
}
}
stats := tree.Stats()
fmt.Printf(" Put %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)
assert.Less(0, tree.Len())
assertTreeCheck(t, tree, false)

// find
tree.ResetStats()
start = time.Now()
for _, k := range keys {
tree.Exist(k)
}
stats = tree.Stats()
fmt.Printf(" Find %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)

// iterator
tree.ResetStats()
start = time.Now()
for it := tree.Iter(); it.Next(); {
// let it loop
}
stats = tree.Stats()
fmt.Printf(" Iter %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)

// delete
tree.ResetStats()
start = time.Now()
for _, k := range keys {
tree.Delete(k)
}
stats = tree.Stats()
fmt.Printf(" Delete %d keys:\t%vms (%v)\n", len(keys), time.Since(start).Milliseconds(), stats)
assert.Equal(0, tree.Len())
assertTreeCheck(t, tree, false)
}