whatcanGOwrong
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
// Copyright 2017 The Bazel Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package starlark
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHashtable(t *testing.T) {
|
||||
makeTestIntsOnce.Do(makeTestInts)
|
||||
testHashtable(t, make(map[int]bool))
|
||||
}
|
||||
|
||||
func BenchmarkStringHash(b *testing.B) {
|
||||
for len := 1; len <= 1024; len *= 2 {
|
||||
buf := make([]byte, len)
|
||||
rand.New(rand.NewSource(0)).Read(buf)
|
||||
s := string(buf)
|
||||
|
||||
b.Run(fmt.Sprintf("hard-%d", len), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
hashString(s)
|
||||
}
|
||||
})
|
||||
b.Run(fmt.Sprintf("soft-%d", len), func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
softHashString(s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHashtable(b *testing.B) {
|
||||
makeTestIntsOnce.Do(makeTestInts)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
testHashtable(b, nil)
|
||||
}
|
||||
}
|
||||
|
||||
const testIters = 10000
|
||||
|
||||
var (
|
||||
// testInts is a zipf-distributed array of Ints and corresponding ints.
|
||||
// This removes the cost of generating them on the fly during benchmarking.
|
||||
// Without this, Zipf and MakeInt dominate CPU and memory costs, respectively.
|
||||
makeTestIntsOnce sync.Once
|
||||
testInts [3 * testIters]struct {
|
||||
Int Int
|
||||
goInt int
|
||||
}
|
||||
)
|
||||
|
||||
func makeTestInts() {
|
||||
zipf := rand.NewZipf(rand.New(rand.NewSource(0)), 1.1, 1.0, 1000.0)
|
||||
for i := range &testInts {
|
||||
r := int(zipf.Uint64())
|
||||
testInts[i].goInt = r
|
||||
testInts[i].Int = MakeInt(r)
|
||||
}
|
||||
}
|
||||
|
||||
// testHashtable is both a test and a benchmark of hashtable.
|
||||
// When sane != nil, it acts as a test against the semantics of Go's map.
|
||||
func testHashtable(tb testing.TB, sane map[int]bool) {
|
||||
var i int // index into testInts
|
||||
|
||||
var ht hashtable
|
||||
|
||||
// Insert 10000 random ints into the map.
|
||||
for j := 0; j < testIters; j++ {
|
||||
k := testInts[i]
|
||||
i++
|
||||
if err := ht.insert(k.Int, None); err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
if sane != nil {
|
||||
sane[k.goInt] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Do 10000 random lookups in the map.
|
||||
for j := 0; j < testIters; j++ {
|
||||
k := testInts[i]
|
||||
i++
|
||||
_, found, err := ht.lookup(k.Int)
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
if sane != nil {
|
||||
_, found2 := sane[k.goInt]
|
||||
if found != found2 {
|
||||
tb.Fatal("sanity check failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do 10000 random deletes from the map.
|
||||
for j := 0; j < testIters; j++ {
|
||||
k := testInts[i]
|
||||
i++
|
||||
_, found, err := ht.delete(k.Int)
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
if sane != nil {
|
||||
_, found2 := sane[k.goInt]
|
||||
if found != found2 {
|
||||
tb.Fatal("sanity check failed")
|
||||
}
|
||||
delete(sane, k.goInt)
|
||||
}
|
||||
}
|
||||
|
||||
if sane != nil {
|
||||
if int(ht.len) != len(sane) {
|
||||
tb.Fatal("sanity check failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashtableCount(t *testing.T) {
|
||||
const count = 1000
|
||||
ht := new(hashtable)
|
||||
for i := 0; i < count; i++ {
|
||||
ht.insert(MakeInt(i), None)
|
||||
}
|
||||
|
||||
if c, err := ht.count(rangeValue{0, count, 1, count}.Iterate()); err != nil {
|
||||
t.Error(err)
|
||||
} else if c != count {
|
||||
t.Errorf("count doesn't match: expected %d got %d", count, c)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user