Noticed during my audit, the code for cache.CommitKVStoreCacheManager.Reset()
discarded the prior on every invocation i.e.
m = make(map[T(key)]T(value))
However, this can be made fast and conserve memory by using the map clearing idiom
that the Go compiler recognizes i.e.
for key := range m {
delete(m, key)
}
and turns into very fast code, instead of the extraneous map discarding.
The speed up generated is:
```shell
$ benchstat before after
name old time/op new time/op delta
Reset-8 204ns ± 2% 66ns ± 9% -67.86% (p=0.000 n=20+20)
name old alloc/op new alloc/op delta
Reset-8 384B ± 0% 0B -100.00% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
Reset-8 3.00 ± 0% 0.00 -100.00% (p=0.000 n=20+20)
```
Fixes #6681
49 lines
953 B
Go
49 lines
953 B
Go
package cache
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/types"
|
|
)
|
|
|
|
func freshMgr() *CommitKVStoreCacheManager {
|
|
return &CommitKVStoreCacheManager{
|
|
caches: map[string]types.CommitKVStore{
|
|
"a1": nil,
|
|
"alalalalalal": nil,
|
|
},
|
|
}
|
|
}
|
|
|
|
func populate(mgr *CommitKVStoreCacheManager) {
|
|
mgr.caches["this one"] = (types.CommitKVStore)(nil)
|
|
mgr.caches["those ones are the ones"] = (types.CommitKVStore)(nil)
|
|
mgr.caches["very huge key right here and there are we going to ones are the ones"] = (types.CommitKVStore)(nil)
|
|
}
|
|
|
|
func BenchmarkReset(b *testing.B) {
|
|
mgr := freshMgr()
|
|
|
|
b.ResetTimer()
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
mgr.Reset()
|
|
if len(mgr.caches) != 0 {
|
|
b.Fatal("Reset failed")
|
|
}
|
|
populate(mgr)
|
|
if len(mgr.caches) == 0 {
|
|
b.Fatal("populate failed")
|
|
}
|
|
mgr.Reset()
|
|
if len(mgr.caches) != 0 {
|
|
b.Fatal("Reset failed")
|
|
}
|
|
}
|
|
|
|
if mgr == nil {
|
|
b.Fatal("Impossible condition")
|
|
}
|
|
}
|