github.com/dolthub/swiss@v0.2.2-0.20240312182618-f4b2babd2bc1/map_bench_test.go (about) 1 // Copyright 2023 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package swiss 16 17 import ( 18 "math/bits" 19 "math/rand" 20 "strconv" 21 "testing" 22 23 "github.com/stretchr/testify/require" 24 25 "github.com/stretchr/testify/assert" 26 ) 27 28 func BenchmarkStringMaps(b *testing.B) { 29 const keySz = 8 30 sizes := []int{16, 128, 1024, 8192, 131072} 31 for _, n := range sizes { 32 b.Run("n="+strconv.Itoa(n), func(b *testing.B) { 33 b.Run("runtime map", func(b *testing.B) { 34 benchmarkRuntimeMap(b, genStringData(keySz, n)) 35 }) 36 b.Run("swiss.Map", func(b *testing.B) { 37 benchmarkSwissMap(b, genStringData(keySz, n)) 38 }) 39 }) 40 } 41 } 42 43 func BenchmarkInt64Maps(b *testing.B) { 44 sizes := []int{16, 128, 1024, 8192, 131072} 45 for _, n := range sizes { 46 b.Run("n="+strconv.Itoa(n), func(b *testing.B) { 47 b.Run("runtime map", func(b *testing.B) { 48 benchmarkRuntimeMap(b, generateInt64Data(n)) 49 }) 50 b.Run("swiss.Map", func(b *testing.B) { 51 benchmarkSwissMap(b, generateInt64Data(n)) 52 }) 53 }) 54 } 55 } 56 57 func TestMemoryFootprint(t *testing.T) { 58 t.Skip("unskip for memory footprint stats") 59 var samples []float64 60 for n := 10; n <= 10_000; n += 10 { 61 b1 := testing.Benchmark(func(b *testing.B) { 62 // max load factor 7/8 63 m := NewMap[int, int](uint32(n)) 64 require.NotNil(b, m) 65 }) 66 b2 := testing.Benchmark(func(b *testing.B) { 67 // max load factor 6.5/8 68 m := make(map[int]int, n) 69 require.NotNil(b, m) 70 }) 71 x := float64(b1.MemBytes) / float64(b2.MemBytes) 72 samples = append(samples, x) 73 } 74 t.Logf("mean size ratio: %.3f", mean(samples)) 75 } 76 77 func benchmarkRuntimeMap[K comparable](b *testing.B, keys []K) { 78 n := uint32(len(keys)) 79 mod := n - 1 // power of 2 fast modulus 80 require.Equal(b, 1, bits.OnesCount32(n)) 81 m := make(map[K]K, n) 82 for _, k := range keys { 83 m[k] = k 84 } 85 b.ResetTimer() 86 var ok bool 87 for i := 0; i < b.N; i++ { 88 _, ok = m[keys[uint32(i)&mod]] 89 } 90 assert.True(b, ok) 91 b.ReportAllocs() 92 } 93 94 func benchmarkSwissMap[K comparable](b *testing.B, keys []K) { 95 n := uint32(len(keys)) 96 mod := n - 1 // power of 2 fast modulus 97 require.Equal(b, 1, bits.OnesCount32(n)) 98 m := NewMap[K, K](n) 99 for _, k := range keys { 100 m.Put(k, k) 101 } 102 b.ResetTimer() 103 var ok bool 104 for i := 0; i < b.N; i++ { 105 _, ok = m.Get(keys[uint32(i)&mod]) 106 } 107 assert.True(b, ok) 108 b.ReportAllocs() 109 } 110 111 func generateInt64Data(n int) (data []int64) { 112 data = make([]int64, n) 113 var x int64 114 for i := range data { 115 x += rand.Int63n(128) + 1 116 data[i] = x 117 } 118 return 119 } 120 121 func mean(samples []float64) (m float64) { 122 for _, s := range samples { 123 m += s 124 } 125 return m / float64(len(samples)) 126 }