Skip to content

Commit

Permalink
Problem: memiavl performance regression when cache miss (#1166)
Browse files Browse the repository at this point in the history
* Problem: memiavl performance regression when cache miss

Solution:
- make the cache optional

* cleanup
  • Loading branch information
yihuang authored Sep 14, 2023
1 parent a376154 commit 09d8a03
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 46 deletions.
62 changes: 27 additions & 35 deletions memiavl/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"testing"

iavlcache "github.com/cosmos/iavl/cache"
lru "github.com/hashicorp/golang-lru"
"github.com/hashicorp/golang-lru/simplelru"
"github.com/stretchr/testify/require"
"github.com/tidwall/btree"
)
Expand Down Expand Up @@ -39,18 +37,40 @@ func BenchmarkRandomGet(b *testing.B) {
snapshot, err := OpenSnapshot(snapshotDir)
require.NoError(b, err)
defer snapshot.Close()
diskTree := NewFromSnapshot(snapshot, true, 0)

require.Equal(b, targetValue, tree.Get(targetKey))
require.Equal(b, targetValue, diskTree.Get(targetKey))

b.ResetTimer()
b.Run("memiavl", func(b *testing.B) {
require.Equal(b, targetValue, tree.Get(targetKey))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = tree.Get(targetKey)
}
})
b.Run("memiavl-disk", func(b *testing.B) {
diskTree := NewFromSnapshot(snapshot, true, 0)
require.Equal(b, targetValue, diskTree.Get(targetKey))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = diskTree.Get(targetKey)
}
})
b.Run("memiavl-disk-cache-hit", func(b *testing.B) {
diskTree := NewFromSnapshot(snapshot, true, 1)
require.Equal(b, targetValue, diskTree.Get(targetKey))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = diskTree.Get(targetKey)
}
})
b.Run("memiavl-disk-cache-miss", func(b *testing.B) {
diskTree := NewFromSnapshot(snapshot, true, 0)
// enforce an empty cache to emulate cache miss
diskTree.cache = iavlcache.New(0)
require.Equal(b, targetValue, diskTree.Get(targetKey))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = diskTree.Get(targetKey)
}
Expand Down Expand Up @@ -87,34 +107,6 @@ func BenchmarkRandomGet(b *testing.B) {
_, _ = bt32.Get(targetItem)
}
})
b.Run("lru-cache", func(b *testing.B) {
cache, err := lru.NewARC(amount)
require.NoError(b, err)
for _, item := range items {
cache.Add(string(item.key), item.value)
}
v, _ := cache.Get(string(targetItem.key))
require.Equal(b, targetValue, v.([]byte))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = cache.Get(string(targetKey))
}
})
b.Run("simplelru", func(b *testing.B) {
cache, err := simplelru.NewLRU(amount, nil)
require.NoError(b, err)
for _, item := range items {
cache.Add(string(item.key), item.value)
}
v, _ := cache.Get(string(targetItem.key))
require.Equal(b, targetValue, v.([]byte))

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = cache.Get(string(targetKey))
}
})
b.Run("iavl-lru", func(b *testing.B) {
cache := iavlcache.New(amount)
for _, item := range items {
Expand Down
1 change: 0 additions & 1 deletion memiavl/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ require (
github.com/confio/ics23/go v0.9.0
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/iavl v0.21.0-alpha.1.0.20230904092046-df3db2d96583
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263
github.com/stretchr/testify v1.8.4
github.com/tidwall/btree v1.6.0
Expand Down
2 changes: 0 additions & 2 deletions memiavl/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
Expand Down
31 changes: 23 additions & 8 deletions memiavl/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ import (

var emptyHash = sha256.New().Sum(nil)

func NewCache(cacheSize int) cache.Cache {
if cacheSize == 0 {
return nil
}
return cache.New(cacheSize)
}

// verify change sets by replay them to rebuild iavl tree and verify the root hashes
type Tree struct {
version uint32
Expand Down Expand Up @@ -48,7 +55,7 @@ func NewEmptyTree(version uint64, initialVersion uint32, cacheSize int) *Tree {
initialVersion: initialVersion,
// no need to copy if the tree is not backed by snapshot
zeroCopy: true,
cache: cache.New(cacheSize),
cache: NewCache(cacheSize),
}
}

Expand All @@ -69,7 +76,7 @@ func NewFromSnapshot(snapshot *Snapshot, zeroCopy bool, cacheSize int) *Tree {
version: snapshot.Version(),
snapshot: snapshot,
zeroCopy: zeroCopy,
cache: cache.New(cacheSize),
cache: NewCache(cacheSize),
}

if !snapshot.IsEmpty() {
Expand Down Expand Up @@ -104,7 +111,7 @@ func (t *Tree) Copy(cacheSize int) *Tree {
}
newTree := *t
// cache is not copied along because it's not thread-safe to access
newTree.cache = cache.New(cacheSize)
newTree.cache = NewCache(cacheSize)
return &newTree
}

Expand All @@ -125,12 +132,16 @@ func (t *Tree) set(key, value []byte) {
value = []byte{}
}
t.root, _ = setRecursive(t.root, key, value, t.version+1, t.cowVersion)
t.cache.Add(&cacheNode{key, value})
if t.cache != nil {
t.cache.Add(&cacheNode{key, value})
}
}

func (t *Tree) remove(key []byte) {
_, t.root, _ = removeRecursive(t.root, key, t.version+1, t.cowVersion)
t.cache.Remove(key)
if t.cache != nil {
t.cache.Remove(key)
}
}

// SaveVersion increases the version number and optionally updates the hashes
Expand Down Expand Up @@ -191,16 +202,20 @@ func (t *Tree) GetByIndex(index int64) ([]byte, []byte) {
}

func (t *Tree) Get(key []byte) []byte {
if node := t.cache.Get(key); node != nil {
return node.(*cacheNode).value
if t.cache != nil {
if node := t.cache.Get(key); node != nil {
return node.(*cacheNode).value
}
}

_, value := t.GetWithIndex(key)
if value == nil {
return nil
}

t.cache.Add(&cacheNode{key, value})
if t.cache != nil {
t.cache.Add(&cacheNode{key, value})
}
return value
}

Expand Down

0 comments on commit 09d8a03

Please sign in to comment.