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  }