blob: 09eb50dd075083d7c89203d1a25f43da5485c7d6 [file] [log] [blame]
// Copyright 2014 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package btree
import (
"fmt"
"sort"
"testing"
)
const benchmarkTreeSize = 10000
var degrees = []int{2, 8, 32, 64}
func BenchmarkInsert(b *testing.B) {
insertP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
i := 0
for i < b.N {
tr := New(d, less)
for _, m := range insertP {
tr.Set(m.Key, m.Value)
i++
if i >= b.N {
return
}
}
}
})
}
}
func BenchmarkDeleteInsert(b *testing.B) {
insertP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
tr := New(d, less)
for _, m := range insertP {
tr.Set(m.Key, m.Value)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m := insertP[i%benchmarkTreeSize]
tr.Delete(m.Key)
tr.Set(m.Key, m.Value)
}
})
}
}
func BenchmarkDeleteInsertCloneOnce(b *testing.B) {
insertP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
tr := New(d, less)
for _, m := range insertP {
tr.Set(m.Key, m.Value)
}
tr = tr.Clone()
b.ResetTimer()
for i := 0; i < b.N; i++ {
m := insertP[i%benchmarkTreeSize]
tr.Delete(m.Key)
tr.Set(m.Key, m.Value)
}
})
}
}
func BenchmarkDeleteInsertCloneEachTime(b *testing.B) {
insertP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
tr := New(d, less)
for _, m := range insertP {
tr.Set(m.Key, m.Value)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
tr = tr.Clone()
m := insertP[i%benchmarkTreeSize]
tr.Delete(m.Key)
tr.Set(m.Key, m.Value)
}
})
}
}
func BenchmarkDelete(b *testing.B) {
insertP := perm(benchmarkTreeSize)
removeP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
i := 0
for i < b.N {
b.StopTimer()
tr := New(d, less)
for _, v := range insertP {
tr.Set(v.Key, v.Value)
}
b.StartTimer()
for _, m := range removeP {
tr.Delete(m.Key)
i++
if i >= b.N {
return
}
}
if tr.Len() > 0 {
panic(tr.Len())
}
}
})
}
}
func BenchmarkGet(b *testing.B) {
insertP := perm(benchmarkTreeSize)
getP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
i := 0
for i < b.N {
b.StopTimer()
tr := New(d, less)
for _, v := range insertP {
tr.Set(v.Key, v.Value)
}
b.StartTimer()
for _, m := range getP {
tr.Get(m.Key)
i++
if i >= b.N {
return
}
}
}
})
}
}
func BenchmarkGetWithIndex(b *testing.B) {
insertP := perm(benchmarkTreeSize)
getP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
i := 0
for i < b.N {
b.StopTimer()
tr := New(d, less)
for _, v := range insertP {
tr.Set(v.Key, v.Value)
}
b.StartTimer()
for _, m := range getP {
tr.GetWithIndex(m.Key)
i++
if i >= b.N {
return
}
}
}
})
}
}
func BenchmarkGetCloneEachTime(b *testing.B) {
insertP := perm(benchmarkTreeSize)
getP := perm(benchmarkTreeSize)
for _, d := range degrees {
b.Run(fmt.Sprintf("degree=%d", d), func(b *testing.B) {
i := 0
for i < b.N {
b.StopTimer()
tr := New(d, less)
for _, m := range insertP {
tr.Set(m.Key, m.Value)
}
b.StartTimer()
for _, m := range getP {
tr = tr.Clone()
tr.Get(m.Key)
i++
if i >= b.N {
return
}
}
}
})
}
}
func BenchmarkFind(b *testing.B) {
for _, d := range degrees {
var items []item
for i := 0; i < 2*d; i++ {
items = append(items, item{i, i})
}
b.Run(fmt.Sprintf("size=%d", len(items)), func(b *testing.B) {
for _, alg := range []struct {
name string
fun func(Key, []item) (int, bool)
}{
{"binary", findBinary},
{"linear", findLinear},
} {
b.Run(alg.name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
for j := 0; j < len(items); j++ {
alg.fun(items[j].key, items)
}
}
})
}
})
}
}
func findBinary(k Key, s []item) (int, bool) {
i := sort.Search(len(s), func(i int) bool { return less(k, s[i].key) })
// i is the smallest index of s for which key.Less(s[i].Key), or len(s).
if i > 0 && !less(s[i-1], k) {
return i - 1, true
}
return i, false
}
func findLinear(k Key, s []item) (int, bool) {
var i int
for i = 0; i < len(s); i++ {
if less(k, s[i].key) {
break
}
}
if i > 0 && !less(s[i-1].key, k) {
return i - 1, true
}
return i, false
}