github.com/fufuok/utils@v1.0.10/xhash/hasher_xsync_test.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package xhash
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  func TestMakeHashFunc(t *testing.T) {
    14  	type User struct {
    15  		Name string
    16  		City string
    17  	}
    18  
    19  	sHasher := MakeHasher[string]()
    20  	iHasher := MakeHasher[User]()
    21  
    22  	// Not that much to test TBH.
    23  	// check that hash is not always the same
    24  	for i := 0; ; i++ {
    25  		if sHasher("foo") != sHasher("bar") {
    26  			break
    27  		}
    28  		if i >= 100 {
    29  			t.Error("sHasher is always the same")
    30  			break
    31  		}
    32  	}
    33  
    34  	if sHasher("foo") != sHasher("foo") {
    35  		t.Error("sHasher is not deterministic")
    36  	}
    37  
    38  	if iHasher(User{Name: "Ivan", City: "Sofia"}) != iHasher(User{Name: "Ivan", City: "Sofia"}) {
    39  		t.Error("iHasher is not deterministic")
    40  	}
    41  }
    42  
    43  func BenchmarkMakeHashFunc(b *testing.B) {
    44  	type Point struct {
    45  		X, Y, Z int
    46  	}
    47  
    48  	type User struct {
    49  		ID        int
    50  		FirstName string
    51  		LastName  string
    52  		IsActive  bool
    53  		City      string
    54  	}
    55  
    56  	type PadInside struct {
    57  		A int
    58  		B byte
    59  		C int
    60  	}
    61  
    62  	type PadTrailing struct {
    63  		A int
    64  		B byte
    65  	}
    66  
    67  	doBenchmarkMakeHashFunc(b, int64(116))
    68  	doBenchmarkMakeHashFunc(b, int32(116))
    69  	doBenchmarkMakeHashFunc(b, 3.14)
    70  	doBenchmarkMakeHashFunc(b, "test key test key test key test key test key test key test key test key test key ")
    71  	doBenchmarkMakeHashFunc(b, Point{1, 2, 3})
    72  	doBenchmarkMakeHashFunc(b, User{ID: 1, FirstName: "Ivan", LastName: "Ivanov", IsActive: true, City: "Sofia"})
    73  	doBenchmarkMakeHashFunc(b, PadInside{})
    74  	doBenchmarkMakeHashFunc(b, PadTrailing{})
    75  	doBenchmarkMakeHashFunc(b, [1024]byte{})
    76  	doBenchmarkMakeHashFunc(b, [128]Point{})
    77  	doBenchmarkMakeHashFunc(b, [128]User{})
    78  	doBenchmarkMakeHashFunc(b, [128]PadInside{})
    79  	doBenchmarkMakeHashFunc(b, [128]PadTrailing{})
    80  }
    81  
    82  func doBenchmarkMakeHashFunc[T comparable](b *testing.B, val T) {
    83  	hash := MakeHasher[T]()
    84  	b.Run(fmt.Sprintf("%T", val), func(b *testing.B) {
    85  		b.ReportAllocs()
    86  		for i := 0; i < b.N; i++ {
    87  			_ = hash(val)
    88  		}
    89  	})
    90  }
    91  
    92  func TestCollision_MakeHasher(t *testing.T) {
    93  	n := 20_000_000
    94  	sHasher := MakeHasher[string]()
    95  	iHasher := MakeHasher[int]()
    96  	ms := make(map[uint64]string)
    97  	mi := make(map[uint64]int)
    98  	for i := 0; i < n; i++ {
    99  		s := strconv.Itoa(i)
   100  		hs := sHasher(s)
   101  		hi := iHasher(i)
   102  		if v, ok := ms[hs]; ok {
   103  			t.Fatalf("Collision: %s(%d) == %s(%d)", v, sHasher(v), s, sHasher(s))
   104  		}
   105  		if v, ok := mi[hi]; ok {
   106  			t.Fatalf("Collision: %d(%d) == %d(%d)", v, iHasher(v), i, iHasher(i))
   107  		}
   108  		ms[hs] = s
   109  		mi[hi] = i
   110  	}
   111  
   112  	hi := iHasher(7)
   113  	if _, ok := mi[hi]; !ok {
   114  		t.Fatalf("The number 7 should exist")
   115  	}
   116  	if len(ms) != len(mi) || len(ms) != n {
   117  		t.Fatalf("Hash count: %d, %d, %d", len(ms), len(mi), n)
   118  	}
   119  }
   120  
   121  func BenchmarkHasher_MakeHasher(b *testing.B) {
   122  	sHasher := MakeHasher[string]()
   123  	iHasher := MakeHasher[int]()
   124  	b.ReportAllocs()
   125  	b.ResetTimer()
   126  	b.Run("string", func(b *testing.B) {
   127  		for i := 0; i < b.N; i++ {
   128  			_ = sHasher(strconv.Itoa(i))
   129  		}
   130  	})
   131  	b.Run("int", func(b *testing.B) {
   132  		for i := 0; i < b.N; i++ {
   133  			_ = iHasher(i)
   134  		}
   135  	})
   136  }
   137  
   138  func BenchmarkHasher_Parallel_MakeHasher(b *testing.B) {
   139  	sHasher := MakeHasher[string]()
   140  	s := strings.Repeat(testString, 10)
   141  	b.ReportAllocs()
   142  	b.ResetTimer()
   143  	b.RunParallel(func(pb *testing.PB) {
   144  		for pb.Next() {
   145  			_ = sHasher(s)
   146  		}
   147  	})
   148  }
   149  
   150  // go test -run=^$ -benchmem -count=2 -bench=BenchmarkHasher
   151  // goos: linux
   152  // goarch: amd64
   153  // pkg: github.com/fufuok/utils/xhash
   154  // cpu: AMD Ryzen 7 5700G with Radeon Graphics
   155  // BenchmarkHasher_MakeHasher/string-16            48853290                24.60 ns/op            7 B/op          0 allocs/op
   156  // BenchmarkHasher_MakeHasher/string-16            50446735                26.41 ns/op            7 B/op          0 allocs/op
   157  // BenchmarkHasher_MakeHasher/int-16               314223793                3.722 ns/op           0 B/op          0 allocs/op
   158  // BenchmarkHasher_MakeHasher/int-16               327831469                3.681 ns/op           0 B/op          0 allocs/op
   159  // BenchmarkHasher_Parallel_MakeHasher-16          759237190                1.611 ns/op           0 B/op          0 allocs/op
   160  // BenchmarkHasher_Parallel_MakeHasher-16          800960254                1.598 ns/op           0 B/op          0 allocs/op
   161  // BenchmarkHasher_GenHasher64/string-16           43828345                26.33 ns/op            7 B/op          0 allocs/op
   162  // BenchmarkHasher_GenHasher64/string-16           43891936                26.14 ns/op            7 B/op          0 allocs/op
   163  // BenchmarkHasher_GenHasher64/int-16              470061992                2.594 ns/op           0 B/op          0 allocs/op
   164  // BenchmarkHasher_GenHasher64/int-16              459792141                2.596 ns/op           0 B/op          0 allocs/op
   165  // BenchmarkHasher_Parallel_GenHasher64-16         333951942                3.606 ns/op           0 B/op          0 allocs/op
   166  // BenchmarkHasher_Parallel_GenHasher64-16         321419834                3.627 ns/op           0 B/op          0 allocs/op