github.com/parquet-go/parquet-go@v0.21.1-0.20240501160520-b3c3a0c3ed6f/hashprobe/aeshash/aeshash_test.go (about)

     1  package aeshash
     2  
     3  import (
     4  	"encoding/binary"
     5  	"testing"
     6  	"time"
     7  	"unsafe"
     8  )
     9  
    10  //go:noescape
    11  //go:linkname runtime_memhash32 runtime.memhash32
    12  func runtime_memhash32(data unsafe.Pointer, seed uintptr) uintptr
    13  
    14  //go:noescape
    15  //go:linkname runtime_memhash64 runtime.memhash64
    16  func runtime_memhash64(data unsafe.Pointer, seed uintptr) uintptr
    17  
    18  //go:noescape
    19  //go:linkname runtime_memhash runtime.memhash
    20  func runtime_memhash(data unsafe.Pointer, seed, size uintptr) uintptr
    21  
    22  func memhash32(data uint32, seed uintptr) uintptr {
    23  	return runtime_memhash32(unsafe.Pointer(&data), seed)
    24  }
    25  
    26  func memhash64(data uint64, seed uintptr) uintptr {
    27  	return runtime_memhash64(unsafe.Pointer(&data), seed)
    28  }
    29  
    30  func memhash128(data [16]byte, seed uintptr) uintptr {
    31  	return runtime_memhash(unsafe.Pointer(&data), seed, 16)
    32  }
    33  
    34  func TestHash32(t *testing.T) {
    35  	if !Enabled() {
    36  		t.Skip("AES hash not supported on this platform")
    37  	}
    38  
    39  	h0 := memhash32(42, 1)
    40  	h1 := Hash32(42, 1)
    41  
    42  	if h0 != h1 {
    43  		t.Errorf("want=%016x got=%016x", h0, h1)
    44  	}
    45  }
    46  
    47  func TestMultiHash32(t *testing.T) {
    48  	if !Enabled() {
    49  		t.Skip("AES hash not supported on this platform")
    50  	}
    51  
    52  	const N = 10
    53  	hashes := [N]uintptr{}
    54  	values := [N]uint32{}
    55  	seed := uintptr(32)
    56  
    57  	for i := range values {
    58  		values[i] = uint32(i)
    59  	}
    60  
    61  	MultiHash32(hashes[:], values[:], seed)
    62  
    63  	for i := range values {
    64  		h := Hash32(values[i], seed)
    65  
    66  		if h != hashes[i] {
    67  			t.Errorf("hash(%d): want=%016x got=%016x", values[i], h, hashes[i])
    68  		}
    69  	}
    70  }
    71  
    72  func TestHash64(t *testing.T) {
    73  	if !Enabled() {
    74  		t.Skip("AES hash not supported on this platform")
    75  	}
    76  
    77  	h0 := memhash64(42, 1)
    78  	h1 := Hash64(42, 1)
    79  
    80  	if h0 != h1 {
    81  		t.Errorf("want=%016x got=%016x", h0, h1)
    82  	}
    83  }
    84  
    85  func TestMultiHash64(t *testing.T) {
    86  	if !Enabled() {
    87  		t.Skip("AES hash not supported on this platform")
    88  	}
    89  
    90  	const N = 10
    91  	hashes := [N]uintptr{}
    92  	values := [N]uint64{}
    93  	seed := uintptr(64)
    94  
    95  	for i := range values {
    96  		values[i] = uint64(i)
    97  	}
    98  
    99  	MultiHash64(hashes[:], values[:], seed)
   100  
   101  	for i := range values {
   102  		h := Hash64(values[i], seed)
   103  
   104  		if h != hashes[i] {
   105  			t.Errorf("hash(%d): want=%016x got=%016x", values[i], h, hashes[i])
   106  		}
   107  	}
   108  }
   109  
   110  func BenchmarkMultiHash64(b *testing.B) {
   111  	if !Enabled() {
   112  		b.Skip("AES hash not supported on this platform")
   113  	}
   114  
   115  	hashes := [512]uintptr{}
   116  	values := [512]uint64{}
   117  	b.SetBytes(8 * int64(len(hashes)))
   118  	benchmarkHashThroughput(b, func(seed uintptr) int {
   119  		MultiHash64(hashes[:], values[:], seed)
   120  		return len(hashes)
   121  	})
   122  }
   123  
   124  func TestHash128(t *testing.T) {
   125  	if !Enabled() {
   126  		t.Skip("AES hash not supported on this platform")
   127  	}
   128  
   129  	h0 := memhash128([16]byte{0: 42}, 1)
   130  	h1 := Hash128([16]byte{0: 42}, 1)
   131  
   132  	if h0 != h1 {
   133  		t.Errorf("want=%016x got=%016x", h0, h1)
   134  	}
   135  }
   136  
   137  func TestMultiHash128(t *testing.T) {
   138  	if !Enabled() {
   139  		t.Skip("AES hash not supported on this platform")
   140  	}
   141  
   142  	const N = 10
   143  	hashes := [N]uintptr{}
   144  	values := [N][16]byte{}
   145  	seed := uintptr(128)
   146  
   147  	for i := range values {
   148  		binary.LittleEndian.PutUint64(values[i][:8], uint64(i))
   149  	}
   150  
   151  	MultiHash128(hashes[:], values[:], seed)
   152  
   153  	for i := range values {
   154  		h := Hash128(values[i], seed)
   155  
   156  		if h != hashes[i] {
   157  			t.Errorf("hash(%d): want=%016x got=%016x", values[i], h, hashes[i])
   158  		}
   159  	}
   160  }
   161  
   162  func benchmarkHashThroughput(b *testing.B, f func(seed uintptr) int) {
   163  	hashes := int64(0)
   164  	start := time.Now()
   165  
   166  	for i := 0; i < b.N; i++ {
   167  		hashes += int64(f(uintptr(i)))
   168  	}
   169  
   170  	seconds := time.Since(start).Seconds()
   171  	b.ReportMetric(float64(hashes)/seconds, "hash/s")
   172  }