Merge pull request #75 from ava-labs/set-cache

pre-allocate slices in various places
This commit is contained in:
Stephen Buttolph 2020-06-16 23:04:27 -04:00 committed by GitHub
commit ea9dcec5a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 219 additions and 16 deletions

8
cache/lru_cache.go vendored
View File

@ -10,6 +10,10 @@ import (
"github.com/ava-labs/gecko/ids"
)
const (
minCacheSize = 32
)
type entry struct {
Key ids.ID
Value interface{}
@ -59,7 +63,7 @@ func (c *LRU) Flush() {
func (c *LRU) init() {
if c.entryMap == nil {
c.entryMap = make(map[[32]byte]*list.Element)
c.entryMap = make(map[[32]byte]*list.Element, minCacheSize)
}
if c.entryList == nil {
c.entryList = list.New()
@ -134,6 +138,6 @@ func (c *LRU) evict(key ids.ID) {
func (c *LRU) flush() {
c.init()
c.entryMap = make(map[[32]byte]*list.Element)
c.entryMap = make(map[[32]byte]*list.Element, minCacheSize)
c.entryList = list.New()
}

53
cache/lru_cache_benchmark_test.go vendored Normal file
View File

@ -0,0 +1,53 @@
package cache
import (
"crypto/rand"
"testing"
"github.com/ava-labs/gecko/ids"
)
func BenchmarkLRUCachePutSmall(b *testing.B) {
smallLen := 5
cache := &LRU{Size: smallLen}
for n := 0; n < b.N; n++ {
for i := 0; i < smallLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
cache.Put(ids.NewID(idBytes), n)
}
b.StopTimer()
cache.Flush()
b.StartTimer()
}
}
func BenchmarkLRUCachePutMedium(b *testing.B) {
mediumLen := 250
cache := &LRU{Size: mediumLen}
for n := 0; n < b.N; n++ {
for i := 0; i < mediumLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
cache.Put(ids.NewID(idBytes), n)
}
b.StopTimer()
cache.Flush()
b.StartTimer()
}
}
func BenchmarkLRUCachePutLarge(b *testing.B) {
largeLen := 10000
cache := &LRU{Size: largeLen}
for n := 0; n < b.N; n++ {
for i := 0; i < largeLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
cache.Put(ids.NewID(idBytes), n)
}
b.StopTimer()
cache.Flush()
b.StartTimer()
}
}

View File

@ -8,6 +8,10 @@ import (
"strings"
)
const (
minBagSize = 16
)
// Bag is a multiset of IDs.
//
// A bag has the ability to split and filter on it's bits for ease of use for
@ -25,7 +29,7 @@ type Bag struct {
func (b *Bag) init() {
if b.counts == nil {
b.counts = make(map[[32]byte]int)
b.counts = make(map[[32]byte]int, minBagSize)
}
}
@ -72,16 +76,21 @@ func (b *Bag) AddCount(id ID, count int) {
}
// Count returns the number of times the id has been added.
func (b *Bag) Count(id ID) int { return b.counts[*id.ID] }
func (b *Bag) Count(id ID) int {
b.init()
return b.counts[*id.ID]
}
// Len returns the number of times an id has been added.
func (b *Bag) Len() int { return b.size }
// List returns a list of all ids that have been added.
func (b *Bag) List() []ID {
idList := []ID(nil)
idList := make([]ID, len(b.counts), len(b.counts))
i := 0
for id := range b.counts {
idList = append(idList, NewID(id))
idList[i] = NewID(id)
i++
}
return idList
}

53
ids/bag_benchmark_test.go Normal file
View File

@ -0,0 +1,53 @@
package ids
import (
"crypto/rand"
"testing"
)
//
func BenchmarkBagListSmall(b *testing.B) {
smallLen := 5
bag := Bag{}
for i := 0; i < smallLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
bag.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
bag.List()
}
}
func BenchmarkBagListMedium(b *testing.B) {
mediumLen := 25
bag := Bag{}
for i := 0; i < mediumLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
bag.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
bag.List()
}
}
func BenchmarkBagListLarge(b *testing.B) {
largeLen := 100000
bag := Bag{}
for i := 0; i < largeLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
bag.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
bag.List()
}
}

View File

@ -18,8 +18,8 @@ func TestBagAdd(t *testing.T) {
} else if count := bag.Count(id1); count != 0 {
t.Fatalf("Bag.Count returned %d expected %d", count, 0)
} else if size := bag.Len(); size != 0 {
t.Fatalf("Bag.Len returned %d expected %d", count, 0)
} else if list := bag.List(); list != nil {
t.Fatalf("Bag.Len returned %d elements expected %d", count, 0)
} else if list := bag.List(); len(list) != 0 {
t.Fatalf("Bag.List returned %v expected %v", list, nil)
} else if mode, freq := bag.Mode(); !mode.IsZero() {
t.Fatalf("Bag.Mode[0] returned %s expected %s", mode, ID{})

View File

@ -7,11 +7,19 @@ import (
"strings"
)
const (
// The minimum capacity of a set
minSetSize = 16
)
// Set is a set of IDs
type Set map[[32]byte]bool
func (ids *Set) init(size int) {
if *ids == nil {
if minSetSize > size {
size = minSetSize
}
*ids = make(map[[32]byte]bool, size)
}
}
@ -70,9 +78,11 @@ func (ids *Set) Clear() { *ids = nil }
// List converts this set into a list
func (ids Set) List() []ID {
idList := []ID(nil)
idList := make([]ID, ids.Len(), ids.Len())
i := 0
for id := range ids {
idList = append(idList, NewID(id))
idList[i] = NewID(id)
i++
}
return idList
}

53
ids/set_benchmark_test.go Normal file
View File

@ -0,0 +1,53 @@
package ids
import (
"crypto/rand"
"testing"
)
//
func BenchmarkSetListSmall(b *testing.B) {
smallLen := 5
set := Set{}
for i := 0; i < smallLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
set.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
set.List()
}
}
func BenchmarkSetListMedium(b *testing.B) {
mediumLen := 25
set := Set{}
for i := 0; i < mediumLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
set.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
set.List()
}
}
func BenchmarkSetListLarge(b *testing.B) {
largeLen := 100000
set := Set{}
for i := 0; i < largeLen; i++ {
var idBytes [32]byte
rand.Read(idBytes[:])
NewID(idBytes)
set.Add(NewID(idBytes))
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
set.List()
}
}

View File

@ -5,11 +5,18 @@ package ids
import "strings"
const (
minShortSetSize = 16
)
// ShortSet is a set of ShortIDs
type ShortSet map[[20]byte]bool
func (ids *ShortSet) init(size int) {
if *ids == nil {
if minShortSetSize > size {
size = minShortSetSize
}
*ids = make(map[[20]byte]bool, size)
}
}
@ -65,9 +72,11 @@ func (ids ShortSet) CappedList(size int) []ShortID {
// List converts this set into a list
func (ids ShortSet) List() []ShortID {
idList := make([]ShortID, len(ids))[:0]
idList := make([]ShortID, len(ids), len(ids))
i := 0
for id := range ids {
idList = append(idList, NewShortID(id))
idList[i] = NewShortID(id)
i++
}
return idList
}

View File

@ -8,12 +8,16 @@ import (
"strings"
)
const (
minUniqueBagSize = 16
)
// UniqueBag ...
type UniqueBag map[[32]byte]BitSet
func (b *UniqueBag) init() {
if *b == nil {
*b = make(map[[32]byte]BitSet)
*b = make(map[[32]byte]BitSet, minUniqueBagSize)
}
}

View File

@ -7,6 +7,10 @@ import (
"github.com/ava-labs/gecko/ids"
)
const (
minRequestsSize = 32
)
type req struct {
vdr ids.ShortID
id uint32
@ -22,7 +26,7 @@ type Requests struct {
// are only in one request at a time.
func (r *Requests) Add(vdr ids.ShortID, requestID uint32, containerID ids.ID) {
if r.reqsToID == nil {
r.reqsToID = make(map[[20]byte]map[uint32]ids.ID)
r.reqsToID = make(map[[20]byte]map[uint32]ids.ID, minRequestsSize)
}
vdrKey := vdr.Key()
vdrReqs, ok := r.reqsToID[vdrKey]
@ -33,7 +37,7 @@ func (r *Requests) Add(vdr ids.ShortID, requestID uint32, containerID ids.ID) {
vdrReqs[requestID] = containerID
if r.idToReq == nil {
r.idToReq = make(map[[32]byte]req)
r.idToReq = make(map[[32]byte]req, minRequestsSize)
}
r.idToReq[containerID.Key()] = req{
vdr: vdr,

View File

@ -10,12 +10,16 @@ import (
"github.com/ava-labs/gecko/ids"
)
const (
minBlockerSize = 16
)
// Blocker tracks objects that are blocked
type Blocker map[[32]byte][]Blockable
func (b *Blocker) init() {
if *b == nil {
*b = make(map[[32]byte][]Blockable)
*b = make(map[[32]byte][]Blockable, minBlockerSize)
}
}