beacon-node/state: alloc 1more item for append case (#12832)

* beacon-chain/state/attenstation: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/eth1: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/misc: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/participation: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* beacon-chain/state/validator: alloc +1 items for append

Signed-off-by: jsvisa <delweng@gmail.com>

* Add some benchmarks

* Evaluate append vs copy. Apply results

* fix copy issue

* revert copy changes from a5ba8d4352

---------

Signed-off-by: jsvisa <delweng@gmail.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
This commit is contained in:
Delweng
2023-10-03 15:41:55 -05:00
committed by GitHub
parent 58c0899676
commit f812bdcf60
11 changed files with 221 additions and 18 deletions

View File

@@ -86,6 +86,10 @@ go_test(
"readonly_validator_test.go",
"references_test.go",
"setters_attestation_test.go",
"setters_eth1_test.go",
"setters_misc_test.go",
"setters_participation_test.go",
"setters_validator_test.go",
"setters_withdrawal_test.go",
"state_fuzz_test.go",
"state_test.go",

View File

@@ -90,8 +90,8 @@ func (b *BeaconState) AppendPreviousEpochAttestations(val *ethpb.PendingAttestat
}
if b.sharedFieldReferences[types.PreviousEpochAttestations].Refs() > 1 {
atts = make([]*ethpb.PendingAttestation, len(b.previousEpochAttestations))
copy(atts, b.previousEpochAttestations)
atts = make([]*ethpb.PendingAttestation, 0, len(b.previousEpochAttestations)+1)
atts = append(atts, b.previousEpochAttestations...)
b.sharedFieldReferences[types.PreviousEpochAttestations].MinusRef()
b.sharedFieldReferences[types.PreviousEpochAttestations] = stateutil.NewRef(1)
}

View File

@@ -74,3 +74,27 @@ func TestAppendBeyondIndicesLimit(t *testing.T) {
assert.Equal(t, true, s.rebuildTrie[types.Validators])
assert.Equal(t, len(s.dirtyIndices[types.Validators]), 0)
}
func BenchmarkAppendPreviousEpochAttestations(b *testing.B) {
st, err := InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(b, err)
max := uint64(params.BeaconConfig().PreviousEpochAttestationsLength())
if max < 2 {
b.Fatalf("previous epoch attestations length is less than 2: %d", max)
}
for i := uint64(0); i < max-2; i++ {
err := st.AppendPreviousEpochAttestations(&ethpb.PendingAttestation{Data: &ethpb.AttestationData{Slot: primitives.Slot(i)}})
require.NoError(b, err)
}
b.ResetTimer()
ref := st.Copy()
for i := 0; i < b.N; i++ {
err := ref.AppendPreviousEpochAttestations(&ethpb.PendingAttestation{Data: &ethpb.AttestationData{Slot: primitives.Slot(i)}})
require.NoError(b, err)
ref = st.Copy()
}
}

View File

@@ -50,8 +50,8 @@ func (b *BeaconState) AppendEth1DataVotes(val *ethpb.Eth1Data) error {
votes := b.eth1DataVotes
if b.sharedFieldReferences[types.Eth1DataVotes].Refs() > 1 {
// Copy elements in underlying array by reference.
votes = make([]*ethpb.Eth1Data, len(b.eth1DataVotes))
copy(votes, b.eth1DataVotes)
votes = make([]*ethpb.Eth1Data, 0, len(b.eth1DataVotes)+1)
votes = append(votes, b.eth1DataVotes...)
b.sharedFieldReferences[types.Eth1DataVotes].MinusRef()
b.sharedFieldReferences[types.Eth1DataVotes] = stateutil.NewRef(1)
}

View File

@@ -0,0 +1,39 @@
package state_native_test
import (
"testing"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/config/params"
eth "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func BenchmarkAppendEth1DataVotes(b *testing.B) {
st, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(b, err)
max := params.BeaconConfig().Eth1DataVotesLength()
if max < 2 {
b.Fatalf("Eth1DataVotesLength is less than 2")
}
for i := uint64(0); i < max-2; i++ {
err := st.AppendEth1DataVotes(&ethpb.Eth1Data{
DepositCount: i,
DepositRoot: make([]byte, 64),
BlockHash: make([]byte, 64),
})
require.NoError(b, err)
}
ref := st.Copy()
for i := 0; i < b.N; i++ {
err := ref.AppendEth1DataVotes(&eth.Eth1Data{DepositCount: uint64(i)})
require.NoError(b, err)
ref = st.Copy()
}
}

View File

@@ -118,8 +118,8 @@ func (b *BeaconState) AppendHistoricalRoots(root [32]byte) error {
roots := b.historicalRoots
if b.sharedFieldReferences[types.HistoricalRoots].Refs() > 1 {
roots = make([][32]byte, len(b.historicalRoots))
copy(roots, b.historicalRoots)
roots = make([][32]byte, 0, len(b.historicalRoots)+1)
roots = append(roots, b.historicalRoots...)
b.sharedFieldReferences[types.HistoricalRoots].MinusRef()
b.sharedFieldReferences[types.HistoricalRoots] = stateutil.NewRef(1)
}
@@ -141,8 +141,8 @@ func (b *BeaconState) AppendHistoricalSummaries(summary *ethpb.HistoricalSummary
summaries := b.historicalSummaries
if b.sharedFieldReferences[types.HistoricalSummaries].Refs() > 1 {
summaries = make([]*ethpb.HistoricalSummary, len(b.historicalSummaries))
copy(summaries, b.historicalSummaries)
summaries = make([]*ethpb.HistoricalSummary, 0, len(b.historicalSummaries)+1)
summaries = append(summaries, b.historicalSummaries...)
b.sharedFieldReferences[types.HistoricalSummaries].MinusRef()
b.sharedFieldReferences[types.HistoricalSummaries] = stateutil.NewRef(1)
}

View File

@@ -0,0 +1,62 @@
package state_native_test
import (
"testing"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func BenchmarkAppendHistoricalRoots(b *testing.B) {
st, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(b, err)
max := params.BeaconConfig().HistoricalRootsLimit
if max < 2 {
b.Fatalf("HistoricalRootsLimit is less than 2: %d", max)
}
root := bytesutil.ToBytes32([]byte{0, 1, 2, 3, 4, 5})
for i := uint64(0); i < max-2; i++ {
err := st.AppendHistoricalRoots(root)
require.NoError(b, err)
}
ref := st.Copy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := ref.AppendHistoricalRoots(root)
require.NoError(b, err)
ref = st.Copy()
}
}
func BenchmarkAppendHistoricalSummaries(b *testing.B) {
st, err := state_native.InitializeFromProtoCapella(&ethpb.BeaconStateCapella{})
require.NoError(b, err)
max := params.BeaconConfig().HistoricalRootsLimit
if max < 2 {
b.Fatalf("HistoricalRootsLimit is less than 2: %d", max)
}
for i := uint64(0); i < max-2; i++ {
err := st.AppendHistoricalSummaries(&ethpb.HistoricalSummary{})
require.NoError(b, err)
}
ref := st.Copy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
err := ref.AppendHistoricalSummaries(&ethpb.HistoricalSummary{})
require.NoError(b, err)
ref = st.Copy()
}
}

View File

@@ -57,8 +57,8 @@ func (b *BeaconState) AppendCurrentParticipationBits(val byte) error {
participation := b.currentEpochParticipation
if b.sharedFieldReferences[types.CurrentEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.currentEpochParticipation))
copy(participation, b.currentEpochParticipation)
participation = make([]byte, 0, len(b.currentEpochParticipation)+1)
participation = append(participation, b.currentEpochParticipation...)
b.sharedFieldReferences[types.CurrentEpochParticipationBits].MinusRef()
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
}
@@ -81,8 +81,8 @@ func (b *BeaconState) AppendPreviousParticipationBits(val byte) error {
bits := b.previousEpochParticipation
if b.sharedFieldReferences[types.PreviousEpochParticipationBits].Refs() > 1 {
bits = make([]byte, len(b.previousEpochParticipation))
copy(bits, b.previousEpochParticipation)
bits = make([]byte, 0, len(b.previousEpochParticipation)+1)
bits = append(bits, b.previousEpochParticipation...)
b.sharedFieldReferences[types.PreviousEpochParticipationBits].MinusRef()
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1)
}
@@ -107,8 +107,8 @@ func (b *BeaconState) ModifyPreviousParticipationBits(mutator func(val []byte) (
participation := b.previousEpochParticipation
if b.sharedFieldReferences[types.PreviousEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.previousEpochParticipation))
copy(participation, b.previousEpochParticipation)
participation = make([]byte, 0, len(b.previousEpochParticipation)+1)
participation = append(participation, b.previousEpochParticipation...)
b.sharedFieldReferences[types.PreviousEpochParticipationBits].MinusRef()
b.sharedFieldReferences[types.PreviousEpochParticipationBits] = stateutil.NewRef(1)
}
@@ -142,8 +142,8 @@ func (b *BeaconState) ModifyCurrentParticipationBits(mutator func(val []byte) ([
participation := b.currentEpochParticipation
if b.sharedFieldReferences[types.CurrentEpochParticipationBits].Refs() > 1 {
// Copy elements in underlying array by reference.
participation = make([]byte, len(b.currentEpochParticipation))
copy(participation, b.currentEpochParticipation)
participation = make([]byte, 0, len(b.currentEpochParticipation)+1)
participation = append(participation, b.currentEpochParticipation...)
b.sharedFieldReferences[types.CurrentEpochParticipationBits].MinusRef()
b.sharedFieldReferences[types.CurrentEpochParticipationBits] = stateutil.NewRef(1)
}

View File

@@ -0,0 +1,27 @@
package state_native_test
import (
"testing"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func BenchmarkParticipationBits(b *testing.B) {
st, err := state_native.InitializeFromProtoCapella(&ethpb.BeaconStateCapella{})
require.NoError(b, err)
max := uint64(16777216)
for i := uint64(0); i < max-2; i++ {
require.NoError(b, st.AppendCurrentParticipationBits(byte(1)))
}
ref := st.Copy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(b, ref.AppendCurrentParticipationBits(byte(2)))
ref = st.Copy()
}
}

View File

@@ -190,7 +190,8 @@ func (b *BeaconState) AppendBalance(bal uint64) error {
bals := b.balances
if b.sharedFieldReferences[types.Balances].Refs() > 1 {
bals = b.balancesVal()
bals = make([]uint64, 0, len(b.balances)+1)
bals = append(bals, b.balances...)
b.sharedFieldReferences[types.Balances].MinusRef()
b.sharedFieldReferences[types.Balances] = stateutil.NewRef(1)
}
@@ -213,7 +214,8 @@ func (b *BeaconState) AppendInactivityScore(s uint64) error {
scores := b.inactivityScores
if b.sharedFieldReferences[types.InactivityScores].Refs() > 1 {
scores = b.inactivityScoresVal()
scores = make([]uint64, 0, len(b.inactivityScores)+1)
scores = append(scores, b.inactivityScores...)
b.sharedFieldReferences[types.InactivityScores].MinusRef()
b.sharedFieldReferences[types.InactivityScores] = stateutil.NewRef(1)
}

View File

@@ -0,0 +1,45 @@
package state_native_test
import (
"testing"
state_native "github.com/prysmaticlabs/prysm/v4/beacon-chain/state/state-native"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/testing/require"
)
func BenchmarkAppendBalance(b *testing.B) {
st, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(b, err)
max := uint64(16777216)
for i := uint64(0); i < max-2; i++ {
require.NoError(b, st.AppendBalance(i))
}
ref := st.Copy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(b, ref.AppendBalance(uint64(i)))
ref = st.Copy()
}
}
func BenchmarkAppendInactivityScore(b *testing.B) {
st, err := state_native.InitializeFromProtoCapella(&ethpb.BeaconStateCapella{})
require.NoError(b, err)
max := uint64(16777216)
for i := uint64(0); i < max-2; i++ {
require.NoError(b, st.AppendInactivityScore(i))
}
ref := st.Copy()
b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(b, ref.AppendInactivityScore(uint64(i)))
ref = st.Copy()
}
}