Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Benchmarks.0 #1

Merged
merged 3 commits into from
Nov 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 0 additions & 15 deletions inmem/inmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
)

type inmemStore struct {
lk sync.Mutex
nonce atomic.Int64
mp map[string][]byte
ttIdx map[string]*ttIndex
Expand All @@ -26,19 +25,11 @@ func New() gkvstore.Store {
}
}

func (i *inmemStore) synchronize() func() {
i.lk.Lock()
return func() {
i.lk.Unlock()
}
}

func key(item gkvstore.Item) string {
return fmt.Sprintf("/%s/%s", item.GetNamespace(), item.GetID())
}

func (i *inmemStore) Create(ctx context.Context, item gkvstore.Item) error {
defer i.synchronize()()

if ids, ok := item.(gkvstore.IDSetter); ok {
ids.SetID(fmt.Sprintf("%d", i.nonce.Inc()))
Expand Down Expand Up @@ -71,7 +62,6 @@ func (i *inmemStore) Create(ctx context.Context, item gkvstore.Item) error {
}

func (i *inmemStore) Read(ctx context.Context, item gkvstore.Item) error {
defer i.synchronize()()

itemBuf, found := i.mp[key(item)]
if !found {
Expand All @@ -82,7 +72,6 @@ func (i *inmemStore) Read(ctx context.Context, item gkvstore.Item) error {
}

func (i *inmemStore) Update(ctx context.Context, item gkvstore.Item) error {
defer i.synchronize()()

if tt, ok := item.(gkvstore.TimeTracker); ok {
ttIdx, exists := i.ttIdx[item.GetNamespace()]
Expand All @@ -106,7 +95,6 @@ func (i *inmemStore) Update(ctx context.Context, item gkvstore.Item) error {
}

func (i *inmemStore) Delete(ctx context.Context, item gkvstore.Item) error {
defer i.synchronize()()

itemBuf, found := i.mp[key(item)]
if found {
Expand Down Expand Up @@ -141,9 +129,7 @@ func (i *inmemStore) List(
skip--
continue
}
i.lk.Lock()
val, found := i.mp[k]
i.lk.Unlock()
if !found {
// best effort continue
continue
Expand All @@ -164,7 +150,6 @@ func (i *inmemStore) List(
switch opts.Sort {
case gkvstore.SortNatural:
go func() {
defer i.synchronize()()
defer close(res)

count := 0
Expand Down
70 changes: 70 additions & 0 deletions sync/sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package syncstore

import (
"context"
"sync"

"github.com/plexsysio/gkvstore"
)

type syncStore struct {
gkvstore.Store

mu sync.RWMutex
}

func New(st gkvstore.Store) gkvstore.Store {
return &syncStore{
Store: st,
}
}

func (t *syncStore) Create(ctx context.Context, item gkvstore.Item) error {
t.mu.Lock()
defer t.mu.Unlock()

return t.Store.Create(context.TODO(), item)
}

func (t *syncStore) Read(ctx context.Context, item gkvstore.Item) error {
t.mu.RLock()
defer t.mu.RUnlock()

return t.Store.Read(context.TODO(), item)
}

func (t *syncStore) Update(ctx context.Context, item gkvstore.Item) error {
t.mu.Lock()
defer t.mu.Unlock()

return t.Store.Update(context.TODO(), item)
}

func (t *syncStore) Delete(ctx context.Context, item gkvstore.Item) error {
t.mu.Lock()
defer t.mu.Unlock()

return t.Store.Delete(context.TODO(), item)
}

func (t *syncStore) List(ctx context.Context, factory gkvstore.Factory, opts gkvstore.ListOpt) (<-chan *gkvstore.Result, error) {
t.mu.RLock()

resChan, err := t.Store.List(ctx, factory, opts)
if err != nil {
t.mu.RUnlock()
return resChan, err
}

relayChan := make(chan *gkvstore.Result)
go func() {
defer close(relayChan)
defer t.mu.RUnlock()

for res := range resChan {
relayChan <- res
}
}()

return relayChan, nil
}
17 changes: 17 additions & 0 deletions sync/sync_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package syncstore_test

import (
"testing"

"github.com/plexsysio/gkvstore/inmem"
"github.com/plexsysio/gkvstore/sync"
"github.com/plexsysio/gkvstore/testsuite"
)

func TestSuite(t *testing.T) {
testsuite.RunTestsuite(t, syncstore.New(inmem.New()), testsuite.Advanced)
}

func BenchmarkSuite(b *testing.B) {
testsuite.BenchmarkSuite(b, syncstore.New(inmem.New()))
}
142 changes: 114 additions & 28 deletions testsuite/benchmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,86 @@ func (t *testBStruct) Unmarshal(buf []byte) error {
return gob.NewDecoder(bw).Decode(t)
}

func BenchmarkCreate(sb *testing.B, st gkvstore.Store, size int) {
func (t *testBStruct) edit(buf []byte) {
idx := rand.Intn(len(t.Val) - len(buf) - 1)
copy(t.Val[idx:idx+len(buf)], buf)
}

func (t *testBStruct) setKey(key string) {
t.Key = key
}

type testCStruct struct {
Key string
Val []byte
Size int64
}

func newStructC(size int) *testCStruct {
return &testCStruct{Size: int64(size)}
}

func (t *testCStruct) GetNamespace() string { return "testStruct" }

func (t *testCStruct) GetID() string { return t.Key }

func (t *testCStruct) SetID(id string) { t.Key = id }

func (t *testCStruct) Marshal() ([]byte, error) {
if t.Val == nil {
t.Val = make([]byte, t.Size-32)
_, err := rand.Read(t.Val)
if err != nil {
return nil, err
}
}
var buf bytes.Buffer
defer buf.Reset()
err := gob.NewEncoder(&buf).Encode(t)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}

func (t *testCStruct) edit(buf []byte) {
idx := rand.Intn(len(t.Val) - len(buf) - 1)
copy(t.Val[idx:idx+len(buf)], buf)
}

func (t *testCStruct) setKey(key string) {
t.Key = key
}

type testStructHelper interface {
edit([]byte)
setKey(string)
}

func (t *testCStruct) Unmarshal(buf []byte) error {
bw := bytes.NewBuffer(buf)
defer bw.Reset()
return gob.NewDecoder(bw).Decode(t)
}

func BenchmarkCreate(sb *testing.B, st gkvstore.Store, newStruct func() gkvstore.Item) {
sb.ReportAllocs()
sb.ResetTimer()

for n := 0; n < sb.N; n++ {
it := newStruct(size)
it := newStruct()
err := st.Create(context.TODO(), it)
if err != nil {
sb.Fatal(err)
}
}
}

func BenchmarkUpdate(sb *testing.B, st gkvstore.Store, size int) {
func BenchmarkUpdate(sb *testing.B, st gkvstore.Store, newStruct func() gkvstore.Item) {

var items []*testBStruct
var items []gkvstore.Item
for n := 0; n < sb.N; n++ {
it := newStruct(size)
it := newStruct()
err := st.Create(context.TODO(), it)
if err != nil {
sb.Fatal(err)
Expand All @@ -95,18 +157,18 @@ func BenchmarkUpdate(sb *testing.B, st gkvstore.Store, size int) {
sb.ResetTimer()

for _, v := range items {
copy(v.Val[:20], editBuf)
v.(testStructHelper).edit(editBuf)
err := st.Update(context.TODO(), v)
if err != nil {
sb.Fatal(err)
}
}
}

func BenchmarkRead(sb *testing.B, st gkvstore.Store, size int) {
func BenchmarkRead(sb *testing.B, st gkvstore.Store, newStruct func() gkvstore.Item) {

for n := 0; n < sb.N; n++ {
it := newStruct(size)
it := newStruct()
err := st.Create(context.TODO(), it)
if err != nil {
sb.Fatal(err)
Expand All @@ -117,8 +179,8 @@ func BenchmarkRead(sb *testing.B, st gkvstore.Store, size int) {
sb.ResetTimer()

for n := 0; n < sb.N; n++ {
it := newStruct(size)
it.Key = fmt.Sprintf("%d", n+1)
it := newStruct()
it.(testStructHelper).setKey(fmt.Sprintf("%d", n+1))

err := st.Read(context.TODO(), it)
if err != nil {
Expand All @@ -128,24 +190,48 @@ func BenchmarkRead(sb *testing.B, st gkvstore.Store, size int) {
}

func BenchmarkSuite(b *testing.B, st gkvstore.Store) {
b.Run("64B", func(sb *testing.B) {
sb.Run("Create", func(sb2 *testing.B) { BenchmarkCreate(sb2, st, 64) })
sb.Run("Read", func(sb2 *testing.B) { BenchmarkRead(sb2, st, 64) })
sb.Run("Update", func(sb2 *testing.B) { BenchmarkUpdate(sb2, st, 64) })
})
b.Run("128B", func(sb *testing.B) {
sb.Run("Create", func(sb2 *testing.B) { BenchmarkCreate(sb2, st, 128) })
sb.Run("Read", func(sb2 *testing.B) { BenchmarkRead(sb2, st, 128) })
sb.Run("Update", func(sb2 *testing.B) { BenchmarkUpdate(sb2, st, 128) })
})
b.Run("256B", func(sb *testing.B) {
sb.Run("Create", func(sb2 *testing.B) { BenchmarkCreate(sb2, st, 256) })
sb.Run("Read", func(sb2 *testing.B) { BenchmarkRead(sb2, st, 256) })
sb.Run("Update", func(sb2 *testing.B) { BenchmarkUpdate(sb2, st, 256) })
b.Run("With time tracker", func(sb1 *testing.B) {
sb1.Run("64B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStruct(64) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStruct(64) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStruct(64) }) })
})
sb1.Run("128B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStruct(128) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStruct(128) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStruct(128) }) })
})
sb1.Run("256B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStruct(256) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStruct(256) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStruct(256) }) })
})
sb1.Run("512B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStruct(512) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStruct(512) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStruct(512) }) })
})
})
b.Run("512B", func(sb *testing.B) {
sb.Run("Create", func(sb2 *testing.B) { BenchmarkCreate(sb2, st, 512) })
sb.Run("Read", func(sb2 *testing.B) { BenchmarkRead(sb2, st, 512) })
sb.Run("Update", func(sb2 *testing.B) { BenchmarkUpdate(sb2, st, 512) })
b.Run("Without time tracker", func(sb1 *testing.B) {
sb1.Run("64B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStructC(64) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStructC(64) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStructC(64) }) })
})
sb1.Run("128B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStructC(128) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStructC(128) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStructC(128) }) })
})
sb1.Run("256B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStructC(256) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStructC(256) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStructC(256) }) })
})
sb1.Run("512B", func(sb2 *testing.B) {
sb2.Run("Create", func(sb3 *testing.B) { BenchmarkCreate(sb3, st, func() gkvstore.Item { return newStructC(512) }) })
sb2.Run("Read", func(sb3 *testing.B) { BenchmarkRead(sb3, st, func() gkvstore.Item { return newStructC(512) }) })
sb2.Run("Update", func(sb3 *testing.B) { BenchmarkUpdate(sb3, st, func() gkvstore.Item { return newStructC(512) }) })
})
})
}