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

performance: Don't preallocate rarely used maps in MakeStateDelta #4715

Merged
merged 7 commits into from
Nov 3, 2022
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
8 changes: 4 additions & 4 deletions ledger/internal/appcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,11 @@ func (cb *roundCowState) AllocateApp(addr basics.Address, aidx basics.AppIndex,
lsd.maxCounts = &space

if global {
cb.mods.Creatables[basics.CreatableIndex(aidx)] = ledgercore.ModifiedCreatable{
cb.mods.AddCreatable(basics.CreatableIndex(aidx), ledgercore.ModifiedCreatable{
Ctype: basics.AppCreatable,
Creator: addr,
Created: true,
}
})
}
return nil
}
Expand Down Expand Up @@ -275,11 +275,11 @@ func (cb *roundCowState) DeallocateApp(addr basics.Address, aidx basics.AppIndex
lsd.kvCow = make(stateDelta)

if global {
cb.mods.Creatables[basics.CreatableIndex(aidx)] = ledgercore.ModifiedCreatable{
cb.mods.AddCreatable(basics.CreatableIndex(aidx), ledgercore.ModifiedCreatable{
Ctype: basics.AppCreatable,
Creator: addr,
Created: false,
}
})
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion ledger/internal/appcow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func getCow(creatables []modsData) *roundCowState {
proto: config.Consensus[protocol.ConsensusCurrentVersion],
}
for _, e := range creatables {
cs.mods.Creatables[e.cidx] = ledgercore.ModifiedCreatable{Ctype: e.ctype, Creator: e.addr, Created: true}
cs.mods.AddCreatable(e.cidx, ledgercore.ModifiedCreatable{Ctype: e.ctype, Creator: e.addr, Created: true})
}
return cs
}
Expand Down
4 changes: 2 additions & 2 deletions ledger/internal/applications.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,12 @@ func (cb *roundCowBase) kvGet(key string) ([]byte, bool, error) {
}

func (cs *roundCowState) kvPut(key string, value []byte) error {
cs.mods.KvMods[key] = ledgercore.KvValueDelta{Data: value}
cs.mods.AddKvMod(key, ledgercore.KvValueDelta{Data: value})
return nil
}

func (cs *roundCowState) kvDel(key string) error {
cs.mods.KvMods[key] = ledgercore.KvValueDelta{Data: nil}
cs.mods.AddKvMod(key, ledgercore.KvValueDelta{Data: nil})
return nil
}

Expand Down
26 changes: 16 additions & 10 deletions ledger/internal/assetcow.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,28 @@ import (

func (cs *roundCowState) AllocateAsset(addr basics.Address, index basics.AssetIndex, global bool) error {
if global {
cs.mods.Creatables[basics.CreatableIndex(index)] = ledgercore.ModifiedCreatable{
Ctype: basics.AssetCreatable,
Creator: addr,
Created: true,
}
cs.mods.AddCreatable(
basics.CreatableIndex(index),
ledgercore.ModifiedCreatable{
Ctype: basics.AssetCreatable,
Creator: addr,
Created: true,
},
)
}
return nil
}

func (cs *roundCowState) DeallocateAsset(addr basics.Address, index basics.AssetIndex, global bool) error {
if global {
cs.mods.Creatables[basics.CreatableIndex(index)] = ledgercore.ModifiedCreatable{
Ctype: basics.AssetCreatable,
Creator: addr,
Created: false,
}
cs.mods.AddCreatable(
basics.CreatableIndex(index),
ledgercore.ModifiedCreatable{
Ctype: basics.AssetCreatable,
Creator: addr,
Created: false,
},
)
}
return nil
}
8 changes: 4 additions & 4 deletions ledger/internal/cow.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func (cb *roundCowState) addTx(txn transactions.Transaction, txid transactions.T
cb.mods.Txids[txid] = ledgercore.IncludedTransactions{LastValid: txn.LastValid, Intra: uint64(len(cb.mods.Txids))}
cb.incTxnCount()
if txn.Lease != [32]byte{} {
cb.mods.Txleases[ledgercore.Txlease{Sender: txn.Sender, Lease: txn.Lease}] = txn.LastValid
cb.mods.AddTxLease(ledgercore.Txlease{Sender: txn.Sender, Lease: txn.Lease}, txn.LastValid)
}
}

Expand Down Expand Up @@ -287,10 +287,10 @@ func (cb *roundCowState) commitToParent() {
cb.commitParent.txnCount += cb.txnCount

for txl, expires := range cb.mods.Txleases {
cb.commitParent.mods.Txleases[txl] = expires
cb.commitParent.mods.AddTxLease(txl, expires)
}
for cidx, delta := range cb.mods.Creatables {
cb.commitParent.mods.Creatables[cidx] = delta
cb.commitParent.mods.AddCreatable(cidx, delta)
}
for addr, smod := range cb.sdeltas {
for aapp, nsd := range smod {
Expand All @@ -309,7 +309,7 @@ func (cb *roundCowState) commitToParent() {
cb.commitParent.mods.StateProofNext = cb.mods.StateProofNext

for key, value := range cb.mods.KvMods {
cb.commitParent.mods.KvMods[key] = value
cb.commitParent.mods.AddKvMod(key, value)
}
Comment on lines 311 to 313
Copy link
Contributor

@cce cce Nov 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it might have been slightly more performant to do:

    if len(cb.mods.KvMods) {
        cb.commitParent.mods.KvMods = make(map[string]KvValueDelta)
	}
	for key, value := range cb.mods.KvMods {
		cb.commitParent.mods.KvMods[key] = value
	}

}

Expand Down
41 changes: 32 additions & 9 deletions ledger/ledgercore/statedelta.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,18 @@ type StateDelta struct {
Accts AccountDeltas

// modified kv pairs (nil == delete)
// not preallocated use .AddKvMod to insert instead of direct assignment
KvMods map[string]KvValueDelta

// new Txids for the txtail and TxnCounter, mapped to txn.LastValid
Txids map[transactions.Txid]IncludedTransactions

// new txleases for the txtail mapped to expiration
// not pre-allocated so use .AddTxLease to insert instead of direct assignment
Txleases map[Txlease]basics.Round

// new creatables creator lookup table
// not pre-allocated so use .AddCreatable to insert instead of direct assignment
Creatables map[basics.CreatableIndex]ModifiedCreatable

// new block header; read-only
Expand Down Expand Up @@ -180,9 +183,11 @@ type AccountDeltas struct {
// AppResources deltas. If app params or local state is deleted, there is a nil value in AppResources.Params or AppResources.State and Deleted flag set
AppResources []AppResourceRecord
// caches for {addr, app id} to app params delta resolution
// not preallocated - use UpsertAppResource instead of inserting directly
appResourcesCache map[AccountApp]int

AssetResources []AssetResourceRecord
AssetResources []AssetResourceRecord
// not preallocated - use UpsertAssertResource instead of inserting directly
assetResourcesCache map[AccountAsset]int
}

Expand All @@ -191,12 +196,9 @@ type AccountDeltas struct {
// This does not play well for AssetConfig and ApplicationCall transactions on scale
func MakeStateDelta(hdr *bookkeeping.BlockHeader, prevTimestamp int64, hint int, stateProofNext basics.Round) StateDelta {
return StateDelta{
Accts: MakeAccountDeltas(hint),
KvMods: make(map[string]KvValueDelta),
Txids: make(map[transactions.Txid]IncludedTransactions, hint),
Txleases: make(map[Txlease]basics.Round),
Accts: MakeAccountDeltas(hint),
Txids: make(map[transactions.Txid]IncludedTransactions, hint),
// asset or application creation are considered as rare events so do not pre-allocate space for them
Creatables: make(map[basics.CreatableIndex]ModifiedCreatable),
Hdr: hdr,
StateProofNext: stateProofNext,
PrevTimestamp: prevTimestamp,
Expand All @@ -209,9 +211,6 @@ func MakeAccountDeltas(hint int) AccountDeltas {
return AccountDeltas{
Accts: make([]BalanceRecord, 0, hint*2),
acctsCache: make(map[basics.Address]int, hint*2),

appResourcesCache: make(map[AccountApp]int),
assetResourcesCache: make(map[AccountAsset]int),
}
}

Expand Down Expand Up @@ -403,6 +402,30 @@ func (ad *AccountDeltas) UpsertAssetResource(addr basics.Address, aidx basics.As
ad.assetResourcesCache[key] = last
}

// AddTxLease adds a new TxLease to the StateDelta
func (sd *StateDelta) AddTxLease(txLease Txlease, expired basics.Round) {
if sd.Txleases == nil {
sd.Txleases = make(map[Txlease]basics.Round)
}
sd.Txleases[txLease] = expired
}

// AddCreatable adds a new Creatable to the StateDelta
func (sd *StateDelta) AddCreatable(idx basics.CreatableIndex, creatable ModifiedCreatable) {
if sd.Creatables == nil {
sd.Creatables = make(map[basics.CreatableIndex]ModifiedCreatable)
}
sd.Creatables[idx] = creatable
}

// AddKvMod adds a new KvMod to the StateDelta
func (sd *StateDelta) AddKvMod(key string, delta KvValueDelta) {
if sd.KvMods == nil {
sd.KvMods = make(map[string]KvValueDelta)
}
sd.KvMods[key] = delta
}

// OptimizeAllocatedMemory by reallocating maps to needed capacity
// For each data structure, reallocate if it would save us at least 50MB aggregate
// If provided maxBalLookback or maxTxnLife are zero, dependent optimizations will not occur.
Expand Down
29 changes: 29 additions & 0 deletions ledger/ledgercore/statedelta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,35 @@ func TestAccountDeltas(t *testing.T) {
a.Equal(sample1, data)
}

func TestMakeStateDeltaMaps(t *testing.T) {
partitiontest.PartitionTest(t)

sd := MakeStateDelta(nil, 0, 23000, basics.Round(2))
require.Nil(t, sd.Txleases)
require.Nil(t, sd.Creatables)
require.Nil(t, sd.KvMods)

sd.AddTxLease(Txlease{}, basics.Round(10))
require.Len(t, sd.Txleases, 1)
sd.AddCreatable(basics.CreatableIndex(5), ModifiedCreatable{})
require.Len(t, sd.Creatables, 1)
sd.AddKvMod("key", KvValueDelta{Data: []byte("value")})
require.Len(t, sd.KvMods, 1)

txLeaseMap := make(map[Txlease]basics.Round)
txLeaseMap[Txlease{}] = basics.Round(10)
require.Equal(t, sd.Txleases, txLeaseMap)

creatableMap := make(map[basics.CreatableIndex]ModifiedCreatable)
creatableMap[basics.CreatableIndex(5)] = ModifiedCreatable{}
require.Equal(t, sd.Creatables, creatableMap)

kvModMap := make(map[string]KvValueDelta)
kvModMap["key"] = KvValueDelta{Data: []byte("value")}
require.Equal(t, sd.KvMods, kvModMap)

}

func BenchmarkMakeStateDelta(b *testing.B) {
hint := 23000
b.ReportAllocs()
Expand Down
2 changes: 1 addition & 1 deletion ledger/txtail_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func TestTxTailDeltaTracking(t *testing.T) {
LastValid: basics.Round(i + 50),
Intra: 0,
}
deltas.Txleases[ledgercore.Txlease{Sender: blk.Payset[0].Txn.Sender, Lease: blk.Payset[0].Txn.Lease}] = basics.Round(i + 50)
deltas.AddTxLease(ledgercore.Txlease{Sender: blk.Payset[0].Txn.Sender, Lease: blk.Payset[0].Txn.Lease}, basics.Round(i+50))

txtail.newBlock(blk, deltas)
txtail.committedUpTo(basics.Round(i))
Expand Down