238 lines
5.6 KiB
Go
238 lines
5.6 KiB
Go
// Copyright 2015 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package hack
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const seed = 4992862800126241206 // set the fixed seed for test
|
|
|
|
func TestSwissTable(t *testing.T) {
|
|
require.True(t, maxTableCapacity == 1024)
|
|
{
|
|
m := make(map[int]int)
|
|
tp := ToSwissMap(m).Type
|
|
require.True(t, tp.GroupSize == 136)
|
|
require.True(t, tp.SlotSize == 16)
|
|
require.True(t, tp.ElemOff == 8)
|
|
}
|
|
{
|
|
m := make(map[int32]int32)
|
|
tp := ToSwissMap(m).Type
|
|
require.True(t, tp.GroupSize == 72)
|
|
require.True(t, tp.SlotSize == 8)
|
|
require.True(t, tp.ElemOff == 4)
|
|
}
|
|
{
|
|
m := make(map[int8]int8)
|
|
tp := ToSwissMap(m).Type
|
|
require.True(t, tp.GroupSize == 24)
|
|
require.True(t, tp.SlotSize == 2)
|
|
require.True(t, tp.ElemOff == 1)
|
|
}
|
|
{
|
|
m := make(map[int64]float64)
|
|
tp := ToSwissMap(m).Type
|
|
require.True(t, tp.GroupSize == 136)
|
|
require.True(t, tp.SlotSize == 16)
|
|
require.True(t, tp.ElemOff == 8)
|
|
}
|
|
{
|
|
m := make(map[complex128]complex128)
|
|
tp := ToSwissMap(m).Type
|
|
require.True(t, tp.GroupSize == 264)
|
|
require.True(t, tp.SlotSize == 32)
|
|
require.True(t, tp.ElemOff == 16)
|
|
}
|
|
{
|
|
const N = 1024
|
|
mp := make(map[uint64]uint64)
|
|
sm := ToSwissMap(mp)
|
|
sm.Data.MockSeedForTest(seed)
|
|
mp[1234] = 5678
|
|
for i := range N {
|
|
mp[uint64(i)] = uint64(i * 2)
|
|
}
|
|
require.Equal(t, N+1, len(mp))
|
|
require.Equal(t, uint64(N+1), sm.Data.Used)
|
|
found := false
|
|
var lastTab *swissMapTable
|
|
|
|
for i := range sm.Data.dirLen {
|
|
table := sm.Data.directoryAt(uintptr(i))
|
|
if table == lastTab {
|
|
continue
|
|
}
|
|
for i := range table.groups.lengthMask + 1 {
|
|
ref := table.groups.group(sm.Type, i)
|
|
require.True(t, (sm.Type.GroupSize-groupSlotsOffset)%sm.Type.SlotSize == 0)
|
|
capacity := ref.cap(sm.Type)
|
|
require.True(t, capacity == swissMapGroupSlots)
|
|
for j := range capacity {
|
|
k, v := *(*uint64)(ref.key(sm.Type, uintptr(j))), *(*uint64)(ref.elem(sm.Type, uintptr(j)))
|
|
if k == 1234 && v == 5678 {
|
|
require.False(t, found)
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
require.True(t, found)
|
|
|
|
oriSeed := sm.Data.seed
|
|
for k := range mp {
|
|
delete(mp, k)
|
|
}
|
|
require.True(t, oriSeed != sm.Data.seed)
|
|
}
|
|
{
|
|
const N = 2000
|
|
mp := make(map[string]int)
|
|
sm := ToSwissMap(mp)
|
|
sm.Data.MockSeedForTest(seed)
|
|
for i := range N {
|
|
mp[fmt.Sprintf("key-%d", i)] = i
|
|
}
|
|
require.Equal(t, N, len(mp))
|
|
require.Equal(t, N, int(sm.Data.Used))
|
|
require.True(t, sm.Type.GroupSize == 200)
|
|
require.True(t, sm.Data.dirLen == 4)
|
|
require.Equal(t, 102608, int(sm.Size()))
|
|
}
|
|
{
|
|
mp := make(map[int]int)
|
|
require.Equal(t, 0, len(mp))
|
|
sm := ToSwissMap(mp)
|
|
sm.Data.MockSeedForTest(seed)
|
|
require.Equal(t, 0, int(sm.Data.Used))
|
|
require.True(t, sm.Type.GroupSize == 136)
|
|
require.Equal(t, 184, int(sm.Size()))
|
|
for i := range 8 {
|
|
mp[i] = i
|
|
}
|
|
require.Equal(t, 8, len(mp))
|
|
require.Equal(t, 184, int(sm.Size()))
|
|
mp[9] = 9
|
|
require.Equal(t, 9, len(mp))
|
|
require.Equal(t, 360, int(sm.Size()))
|
|
}
|
|
|
|
{
|
|
mp := make(map[complex128]complex128)
|
|
m := MemAwareMap[complex128, complex128]{}
|
|
const N = 1024*50 - 1
|
|
delta := m.Init(mp)
|
|
m.MockSeedForTest(seed)
|
|
for i := range N {
|
|
k := complex(float64(i), float64(i))
|
|
d := m.Set(k, k)
|
|
delta += d
|
|
if d > 0 {
|
|
sz := m.RealBytes()
|
|
expMin := sz * 75 / 100
|
|
require.True(t, m.Bytes >= expMin, "ApproxSize %d, RealSize %d, index %d, expMin %d", m.Bytes, sz, i, expMin)
|
|
require.True(t, approxSize(m.groupSize, uint64(m.Len())) >= expMin, "ApproxSize %d, RealSize %d, index %d, expMin %d", m.Bytes, sz, i, expMin)
|
|
}
|
|
}
|
|
sz := m.RealBytes()
|
|
require.True(t, sz == 2165296, sz)
|
|
require.True(t, delta == 2702278, delta)
|
|
require.True(t, delta == int64(m.Bytes))
|
|
require.True(t, seed == m.unwrap().seed)
|
|
clearSeq := m.unwrap().clearSeq
|
|
clear(m.M)
|
|
require.True(t, m.Len() == 0)
|
|
require.True(t, clearSeq+1 == m.unwrap().clearSeq)
|
|
require.True(t, m.unwrap().seed != seed)
|
|
require.True(t, sz == m.RealBytes())
|
|
require.True(t, delta == int64(m.Bytes))
|
|
|
|
m.MockSeedForTest(seed)
|
|
for i := range 1024 {
|
|
k := complex(float64(i), float64(i))
|
|
d, insert := m.SetExt(k, k)
|
|
require.True(t, d == 0)
|
|
require.True(t, insert)
|
|
}
|
|
require.True(t, m.Len() == 1024)
|
|
}
|
|
}
|
|
|
|
var result int
|
|
|
|
var inputs = []struct {
|
|
input int
|
|
}{
|
|
{input: 1},
|
|
{input: 100},
|
|
{input: 10000},
|
|
{input: 1000000},
|
|
}
|
|
|
|
func memAwareIntMap(size int) int {
|
|
var x int
|
|
m := NewMemAwareMap[int, int](0)
|
|
for j := range size {
|
|
m.Set(j, j)
|
|
}
|
|
for j := range size {
|
|
x, _ = m.Get(j)
|
|
}
|
|
return x
|
|
}
|
|
|
|
func nativeIntMap(size int) int {
|
|
var x int
|
|
m := make(map[int]int)
|
|
for j := range size {
|
|
m[j] = j
|
|
}
|
|
|
|
for j := range size {
|
|
x = m[j]
|
|
}
|
|
return x
|
|
}
|
|
|
|
func BenchmarkMemAwareIntMap(b *testing.B) {
|
|
for _, s := range inputs {
|
|
b.Run("MemAwareIntMap_"+strconv.Itoa(s.input), func(b *testing.B) {
|
|
var x int
|
|
for b.Loop() {
|
|
x = memAwareIntMap(s.input)
|
|
}
|
|
result = x
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkNativeIntMap(b *testing.B) {
|
|
for _, s := range inputs {
|
|
b.Run("NativeIntMap_"+strconv.Itoa(s.input), func(b *testing.B) {
|
|
var x int
|
|
for b.Loop() {
|
|
x = nativeIntMap(s.input)
|
|
}
|
|
result = x
|
|
})
|
|
}
|
|
}
|