Skip to content

Commit

Permalink
Add Benchmark MMap (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
QuangTung97 authored Oct 6, 2023
1 parent 45cfd88 commit 0b61379
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 3 deletions.
8 changes: 7 additions & 1 deletion mmap/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,15 @@ type BucketKey[R RootKey] struct {

// String ...
func (k BucketKey[R]) String() string {
rootKey := k.RootKey.String()

var buf strings.Builder

_, _ = buf.WriteString(k.RootKey.String())
// 2 byte for size log
// 8 byte for hash value => can contain 4 byte uint32
buf.Grow(len(rootKey) + 2*len(k.Sep) + 10)

_, _ = buf.WriteString(rootKey)
_, _ = buf.WriteString(k.Sep)
_, _ = buf.WriteString(strconv.FormatInt(int64(k.SizeLog), 10))
_, _ = buf.WriteString(k.Sep)
Expand Down
7 changes: 6 additions & 1 deletion mmap/mmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import (
// RootKey constraints
type RootKey interface {
item.Key

// AvgBucketSizeLog returns the logarithm base 2 of expected average size per bucket
// values should be between [0, 8]
// value = 0 => average 1 element per bucket
// value = 3 => average 8 elements per bucket
AvgBucketSizeLog() uint8
}

Expand Down Expand Up @@ -80,7 +85,7 @@ func New[T Value, R RootKey, K Key](
}
}

// Option ...
// Option an optional value
type Option[T any] struct {
Valid bool
Data T
Expand Down
169 changes: 169 additions & 0 deletions mmap/mmap_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package mmap

import (
"context"
"encoding/binary"
"strconv"
"testing"

"github.com/spaolacci/murmur3"
"github.com/stretchr/testify/assert"

"github.com/QuangTung97/memproxy"
)

type benchValue struct {
rootKey benchRootKey
key benchKey
value int64
}

type benchRootKey struct {
value uint64
}

type benchKey struct {
value uint64
}

const benchKeyNum = 229
const benchValueNum = 331

func newBenchMapCache(pipe memproxy.Pipeline) *Map[benchValue, benchRootKey, benchKey] {
return New[benchValue, benchRootKey, benchKey](
pipe,
unmarshalBenchValue,
func(ctx context.Context, rootKey benchRootKey, hashRange HashRange) func() ([]benchValue, error) {
return func() ([]benchValue, error) {
return []benchValue{
{
rootKey: rootKey,
key: benchKey{
value: benchKeyNum,
},
value: benchValueNum,
},
}, nil
}
},
benchValue.getKey,
)
}

func doGetMapElemFromMemcache(mc memproxy.Memcache, numKeys int) {
pipe := mc.Pipeline(context.Background())
defer pipe.Finish()

mapCache := newBenchMapCache(pipe)

fnList := make([]func() (Option[benchValue], error), 0, numKeys)
for i := 0; i < numKeys; i++ {
fn := mapCache.Get(context.Background(), uint64(numKeys), benchRootKey{
value: uint64(1000 + i),
}, benchKey{
value: benchKeyNum,
})
fnList = append(fnList, fn)
}

for _, fn := range fnList {
result, err := fn()
if err != nil {
panic(err)
}
if !result.Valid {
panic("not valid")
}
if result.Data.value != benchValueNum {
panic("wrong value")
}
}
}

func Benchmark_Proxy__Map_Get_Batch_100(b *testing.B) {
mc := newMemcacheWithProxy(b)

const numKeys = 100

doGetMapElemFromMemcache(mc, numKeys)

b.ResetTimer()

for n := 0; n < b.N; n++ {
doGetMapElemFromMemcache(mc, numKeys)
}
}

func Benchmark_Proxy__Map_Get_Batch_1000(b *testing.B) {
mc := newMemcacheWithProxy(b)

const numKeys = 1000

doGetMapElemFromMemcache(mc, numKeys)

b.ResetTimer()

for n := 0; n < b.N; n++ {
doGetMapElemFromMemcache(mc, numKeys)
}
}

func (v benchValue) getKey() benchKey {
return v.key
}

func (k benchKey) Hash() uint64 {
var data [8]byte
binary.LittleEndian.PutUint64(data[:], k.value)
return murmur3.Sum64(data[:])
}

func (k benchRootKey) String() string {
return strconv.FormatUint(k.value, 10)
}

func (benchRootKey) AvgBucketSizeLog() uint8 {
return 1
}

func (v benchValue) Marshal() ([]byte, error) {
var result [24]byte
binary.LittleEndian.PutUint64(result[:], v.rootKey.value)
binary.LittleEndian.PutUint64(result[8:], v.key.value)
binary.LittleEndian.PutUint64(result[16:], uint64(v.value))
return result[:], nil
}

func unmarshalBenchValue(data []byte) (benchValue, error) {
rootKey := binary.LittleEndian.Uint64(data[:])
key := binary.LittleEndian.Uint64(data[8:])
val := binary.LittleEndian.Uint64(data[16:])

return benchValue{
rootKey: benchRootKey{
value: rootKey,
},
key: benchKey{
value: key,
},
value: int64(val),
}, nil
}

func TestMarshalBenchValue(t *testing.T) {
b := benchValue{
rootKey: benchRootKey{
value: 41,
},
key: benchKey{
value: 31,
},
value: 55,
}
data, err := b.Marshal()
assert.Equal(t, nil, err)

newVal, err := unmarshalBenchValue(data)
assert.Equal(t, nil, err)
assert.Equal(t, b, newVal)
}
6 changes: 5 additions & 1 deletion mmap/mmap_property_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ func clearMemcache() {
}
}

func newMemcacheWithProxy(t *testing.T) memproxy.Memcache {
type cleanerInterface interface {
Cleanup(fn func())
}

func newMemcacheWithProxy(t cleanerInterface) memproxy.Memcache {
clearMemcache()

server1 := proxy.SimpleServerConfig{
Expand Down

0 comments on commit 0b61379

Please sign in to comment.