core: add benchmarks for iterator.Next, MemCached.Seek, Mem.Seek
This commit is contained in:
parent
8d8071f97e
commit
d8210c0137
8 changed files with 199 additions and 29 deletions
|
@ -2,6 +2,7 @@ package core
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
@ -336,32 +337,98 @@ func TestStorageDelete(t *testing.T) {
|
|||
}
|
||||
|
||||
func BenchmarkStorageFind(b *testing.B) {
|
||||
v, contractState, context, chain := createVMAndContractState(b)
|
||||
require.NoError(b, chain.contracts.Management.PutContractState(chain.dao, contractState))
|
||||
for count := 10; count <= 10000; count *= 10 {
|
||||
b.Run(fmt.Sprintf("%dElements", count), func(b *testing.B) {
|
||||
v, contractState, context, chain := createVMAndContractState(b)
|
||||
require.NoError(b, chain.contracts.Management.PutContractState(chain.dao, contractState))
|
||||
|
||||
const count = 100
|
||||
items := make(map[string]state.StorageItem)
|
||||
for i := 0; i < count; i++ {
|
||||
items["abc"+random.String(10)] = random.Bytes(10)
|
||||
}
|
||||
for k, v := range items {
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID, []byte(k), v))
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID+1, []byte(k), v))
|
||||
}
|
||||
changes, err := context.DAO.Persist()
|
||||
require.NoError(b, err)
|
||||
require.NotEqual(b, 0, changes)
|
||||
|
||||
items := make(map[string]state.StorageItem)
|
||||
for i := 0; i < count; i++ {
|
||||
items["abc"+random.String(10)] = random.Bytes(10)
|
||||
}
|
||||
for k, v := range items {
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID, []byte(k), v))
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID+1, []byte(k), v))
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
v.Estack().PushVal(istorage.FindDefault)
|
||||
v.Estack().PushVal("abc")
|
||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: contractState.ID}))
|
||||
b.StartTimer()
|
||||
err := storageFind(context)
|
||||
if err != nil {
|
||||
b.FailNow()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
v.Estack().PushVal(istorage.FindDefault)
|
||||
v.Estack().PushVal("abc")
|
||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: contractState.ID}))
|
||||
b.StartTimer()
|
||||
err := storageFind(context)
|
||||
if err != nil {
|
||||
b.FailNow()
|
||||
func BenchmarkStorageFindIteratorNext(b *testing.B) {
|
||||
for count := 10; count <= 10000; count *= 10 {
|
||||
cases := map[string]int{
|
||||
"Pick1": 1,
|
||||
"PickHalf": count / 2,
|
||||
"PickAll": count,
|
||||
}
|
||||
b.Run(fmt.Sprintf("%dElements", count), func(b *testing.B) {
|
||||
for name, last := range cases {
|
||||
b.Run(name, func(b *testing.B) {
|
||||
v, contractState, context, chain := createVMAndContractState(b)
|
||||
require.NoError(b, chain.contracts.Management.PutContractState(chain.dao, contractState))
|
||||
|
||||
items := make(map[string]state.StorageItem)
|
||||
for i := 0; i < count; i++ {
|
||||
items["abc"+random.String(10)] = random.Bytes(10)
|
||||
}
|
||||
for k, v := range items {
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID, []byte(k), v))
|
||||
require.NoError(b, context.DAO.PutStorageItem(contractState.ID+1, []byte(k), v))
|
||||
}
|
||||
changes, err := context.DAO.Persist()
|
||||
require.NoError(b, err)
|
||||
require.NotEqual(b, 0, changes)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
v.Estack().PushVal(istorage.FindDefault)
|
||||
v.Estack().PushVal("abc")
|
||||
v.Estack().PushVal(stackitem.NewInterop(&StorageContext{ID: contractState.ID}))
|
||||
b.StartTimer()
|
||||
err := storageFind(context)
|
||||
b.StopTimer()
|
||||
if err != nil {
|
||||
b.FailNow()
|
||||
}
|
||||
res := context.VM.Estack().Pop().Item()
|
||||
for i := 0; i < last; i++ {
|
||||
context.VM.Estack().PushVal(res)
|
||||
b.StartTimer()
|
||||
require.NoError(b, iterator.Next(context))
|
||||
b.StopTimer()
|
||||
require.True(b, context.VM.Estack().Pop().Bool())
|
||||
}
|
||||
|
||||
context.VM.Estack().PushVal(res)
|
||||
require.NoError(b, iterator.Next(context))
|
||||
actual := context.VM.Estack().Pop().Bool()
|
||||
if last == count {
|
||||
require.False(b, actual)
|
||||
} else {
|
||||
require.True(b, actual)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newBadgerDBForTesting(t *testing.T) Store {
|
||||
func newBadgerDBForTesting(t testing.TB) Store {
|
||||
bdbDir := t.TempDir()
|
||||
dbConfig := DBConfiguration{
|
||||
Type: "badgerdb",
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newBoltStoreForTesting(t *testing.T) Store {
|
||||
func newBoltStoreForTesting(t testing.TB) Store {
|
||||
d := t.TempDir()
|
||||
testFileName := path.Join(d, "test_bolt_db")
|
||||
boltDBStore, err := NewBoltDBStore(BoltDBOptions{FilePath: testFileName})
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newLevelDBForTesting(t *testing.T) Store {
|
||||
func newLevelDBForTesting(t testing.TB) Store {
|
||||
ldbDir := t.TempDir()
|
||||
dbConfig := DBConfiguration{
|
||||
Type: "leveldb",
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
@ -174,7 +176,82 @@ func TestCachedSeek(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func newMemCachedStoreForTesting(t *testing.T) Store {
|
||||
func benchmarkCachedSeek(t *testing.B, ps Store, psElementsCount, tsElementsCount int) {
|
||||
var (
|
||||
searchPrefix = []byte{1}
|
||||
badPrefix = []byte{2}
|
||||
lowerPrefixGood = append(searchPrefix, 1)
|
||||
lowerPrefixBad = append(badPrefix, 1)
|
||||
deletedPrefixGood = append(searchPrefix, 2)
|
||||
deletedPrefixBad = append(badPrefix, 2)
|
||||
updatedPrefixGood = append(searchPrefix, 3)
|
||||
updatedPrefixBad = append(badPrefix, 3)
|
||||
|
||||
ts = NewMemCachedStore(ps)
|
||||
)
|
||||
for i := 0; i < psElementsCount; i++ {
|
||||
// lower KVs with matching prefix that should be found
|
||||
require.NoError(t, ps.Put(append(lowerPrefixGood, random.Bytes(10)...), []byte("value")))
|
||||
// lower KVs with non-matching prefix that shouldn't be found
|
||||
require.NoError(t, ps.Put(append(lowerPrefixBad, random.Bytes(10)...), []byte("value")))
|
||||
|
||||
// deleted KVs with matching prefix that shouldn't be found
|
||||
key := append(deletedPrefixGood, random.Bytes(10)...)
|
||||
require.NoError(t, ps.Put(key, []byte("deleted")))
|
||||
if i < tsElementsCount {
|
||||
require.NoError(t, ts.Delete(key))
|
||||
}
|
||||
// deleted KVs with non-matching prefix that shouldn't be found
|
||||
key = append(deletedPrefixBad, random.Bytes(10)...)
|
||||
require.NoError(t, ps.Put(key, []byte("deleted")))
|
||||
if i < tsElementsCount {
|
||||
require.NoError(t, ts.Delete(key))
|
||||
}
|
||||
|
||||
// updated KVs with matching prefix that should be found
|
||||
key = append(updatedPrefixGood, random.Bytes(10)...)
|
||||
require.NoError(t, ps.Put(key, []byte("stub")))
|
||||
if i < tsElementsCount {
|
||||
require.NoError(t, ts.Put(key, []byte("updated")))
|
||||
}
|
||||
// updated KVs with non-matching prefix that shouldn't be found
|
||||
key = append(updatedPrefixBad, random.Bytes(10)...)
|
||||
require.NoError(t, ps.Put(key, []byte("stub")))
|
||||
if i < tsElementsCount {
|
||||
require.NoError(t, ts.Put(key, []byte("updated")))
|
||||
}
|
||||
}
|
||||
|
||||
t.ReportAllocs()
|
||||
t.ResetTimer()
|
||||
for n := 0; n < t.N; n++ {
|
||||
ts.Seek(searchPrefix, func(k, v []byte) {})
|
||||
}
|
||||
t.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkCachedSeek(t *testing.B) {
|
||||
var stores = map[string]func(testing.TB) Store{
|
||||
"MemPS": func(t testing.TB) Store {
|
||||
return NewMemoryStore()
|
||||
},
|
||||
"BoltPS": newBoltStoreForTesting,
|
||||
"LevelPS": newLevelDBForTesting,
|
||||
}
|
||||
for psName, newPS := range stores {
|
||||
for psCount := 100; psCount <= 10000; psCount *= 10 {
|
||||
for tsCount := 10; tsCount <= psCount; tsCount *= 10 {
|
||||
t.Run(fmt.Sprintf("%s_%dTSItems_%dPSItems", psName, tsCount, psCount), func(t *testing.B) {
|
||||
ps := newPS(t)
|
||||
benchmarkCachedSeek(t, ps, psCount, tsCount)
|
||||
ps.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newMemCachedStoreForTesting(t testing.TB) Store {
|
||||
return NewMemCachedStore(NewMemoryStore())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,35 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/random"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newMemoryStoreForTesting(t *testing.T) Store {
|
||||
func newMemoryStoreForTesting(t testing.TB) Store {
|
||||
return NewMemoryStore()
|
||||
}
|
||||
|
||||
func BenchmarkMemorySeek(t *testing.B) {
|
||||
for count := 10; count <= 10000; count *= 10 {
|
||||
t.Run(fmt.Sprintf("%dElements", count), func(t *testing.B) {
|
||||
ms := NewMemoryStore()
|
||||
var (
|
||||
searchPrefix = []byte{1}
|
||||
badPrefix = []byte{2}
|
||||
)
|
||||
for i := 0; i < count; i++ {
|
||||
require.NoError(t, ms.Put(append(searchPrefix, random.Bytes(10)...), random.Bytes(10)))
|
||||
require.NoError(t, ms.Put(append(badPrefix, random.Bytes(10)...), random.Bytes(10)))
|
||||
}
|
||||
|
||||
t.ReportAllocs()
|
||||
t.ResetTimer()
|
||||
for n := 0; n < t.N; n++ {
|
||||
ms.Seek(searchPrefix, func(k, v []byte) {})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ type mockedRedisStore struct {
|
|||
mini *miniredis.Miniredis
|
||||
}
|
||||
|
||||
func prepareRedisMock(t *testing.T) (*miniredis.Miniredis, *RedisStore) {
|
||||
func prepareRedisMock(t testing.TB) (*miniredis.Miniredis, *RedisStore) {
|
||||
miniRedis, err := miniredis.Run()
|
||||
require.Nil(t, err, "MiniRedis mock creation error")
|
||||
|
||||
|
@ -37,7 +37,7 @@ func (mrs *mockedRedisStore) Close() error {
|
|||
return err
|
||||
}
|
||||
|
||||
func newRedisStoreForTesting(t *testing.T) Store {
|
||||
func newRedisStoreForTesting(t testing.TB) Store {
|
||||
mock, rs := prepareRedisMock(t)
|
||||
mrs := &mockedRedisStore{RedisStore: *rs, mini: mock}
|
||||
return mrs
|
||||
|
|
|
@ -19,7 +19,7 @@ type kvSeen struct {
|
|||
|
||||
type dbSetup struct {
|
||||
name string
|
||||
create func(*testing.T) Store
|
||||
create func(testing.TB) Store
|
||||
}
|
||||
|
||||
type dbTestFunction func(*testing.T, Store)
|
||||
|
|
Loading…
Reference in a new issue