github.com/google/skylark@v0.0.0-20181101142754-a5f7082aabed/hashtable_test.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package skylark 6 7 import ( 8 "fmt" 9 "math/rand" 10 "testing" 11 ) 12 13 func TestHashtable(t *testing.T) { 14 testHashtable(t, make(map[int]bool)) 15 } 16 17 func BenchmarkStringHash(b *testing.B) { 18 for len := 1; len <= 1024; len *= 2 { 19 buf := make([]byte, len) 20 rand.New(rand.NewSource(0)).Read(buf) 21 s := string(buf) 22 23 b.Run(fmt.Sprintf("hard-%d", len), func(b *testing.B) { 24 for i := 0; i < b.N; i++ { 25 hashString(s) 26 } 27 }) 28 b.Run(fmt.Sprintf("soft-%d", len), func(b *testing.B) { 29 for i := 0; i < b.N; i++ { 30 softHashString(s) 31 } 32 }) 33 } 34 } 35 36 func BenchmarkHashtable(b *testing.B) { 37 // TODO(adonovan): MakeInt probably dominates the cost of this benchmark. 38 // Optimise or avoid it. 39 for i := 0; i < b.N; i++ { 40 testHashtable(b, nil) 41 } 42 } 43 44 // testHashtable is both a test and a benchmark of hashtable. 45 // When sane != nil, it acts as a test against the semantics of Go's map. 46 func testHashtable(tb testing.TB, sane map[int]bool) { 47 zipf := rand.NewZipf(rand.New(rand.NewSource(0)), 1.1, 1.0, 1000.0) 48 var ht hashtable 49 50 // Insert 10000 random ints into the map. 51 for j := 0; j < 10000; j++ { 52 k := int(zipf.Uint64()) 53 if err := ht.insert(MakeInt(k), None); err != nil { 54 tb.Fatal(err) 55 } 56 if sane != nil { 57 sane[k] = true 58 } 59 } 60 61 // Do 10000 random lookups in the map. 62 for j := 0; j < 10000; j++ { 63 k := int(zipf.Uint64()) 64 _, found, err := ht.lookup(MakeInt(k)) 65 if err != nil { 66 tb.Fatal(err) 67 } 68 if sane != nil { 69 _, found2 := sane[k] 70 if found != found2 { 71 tb.Fatal("sanity check failed") 72 } 73 } 74 } 75 76 // Do 10000 random deletes from the map. 77 for j := 0; j < 10000; j++ { 78 k := int(zipf.Uint64()) 79 _, found, err := ht.delete(MakeInt(k)) 80 if err != nil { 81 tb.Fatal(err) 82 } 83 if sane != nil { 84 _, found2 := sane[k] 85 if found != found2 { 86 tb.Fatal("sanity check failed") 87 } 88 delete(sane, k) 89 } 90 } 91 92 if sane != nil { 93 if int(ht.len) != len(sane) { 94 tb.Fatal("sanity check failed") 95 } 96 } 97 }