Skip to content

Commit

Permalink
Additional tests, benchmarks.
Browse files Browse the repository at this point in the history
  • Loading branch information
andreibancioiu committed Dec 12, 2024
1 parent 853f676 commit 7ae6171
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 24 deletions.
4 changes: 4 additions & 0 deletions testscommon/txcachemocks/selectionSessionMock.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
type SelectionSessionMock struct {
mutex sync.Mutex

NumCallsGetAccountState int

AccountStateByAddress map[string]*types.AccountState
GetAccountStateCalled func(address []byte) (*types.AccountState, error)
IsIncorrectlyGuardedCalled func(tx data.TransactionHandler) bool
Expand Down Expand Up @@ -57,6 +59,8 @@ func (mock *SelectionSessionMock) GetAccountState(address []byte) (*types.Accoun
mock.mutex.Lock()
defer mock.mutex.Unlock()

mock.NumCallsGetAccountState++

if mock.GetAccountStateCalled != nil {
return mock.GetAccountStateCalled(address)
}
Expand Down
8 changes: 4 additions & 4 deletions txcache/eviction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ func TestBenchmarkTxCache_DoEviction(t *testing.T) {
// Thread(s) per core: 2
// Core(s) per socket: 4
//
// 0.119274s (TestBenchmarkTxCache_DoEviction/numSenders_=_35000,_numTransactions_=_10)
// 0.484147s (TestBenchmarkTxCache_DoEviction/numSenders_=_100000,_numTransactions_=_5)
// 0.504588s (TestBenchmarkTxCache_DoEviction/numSenders_=_10000,_numTransactions_=_100)
// 0.571885s (TestBenchmarkTxCache_DoEviction/numSenders_=_400000,_numTransactions_=_1)
// 0.092625s (TestBenchmarkTxCache_DoEviction/numSenders_=_35000,_numTransactions_=_10)
// 0.426718s (TestBenchmarkTxCache_DoEviction/numSenders_=_100000,_numTransactions_=_5)
// 0.546757s (TestBenchmarkTxCache_DoEviction/numSenders_=_10000,_numTransactions_=_100)
// 0.542678s (TestBenchmarkTxCache_DoEviction/numSenders_=_400000,_numTransactions_=_1)
}
2 changes: 2 additions & 0 deletions txcache/selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func selectTransactionsFromBunches(session SelectionSession, bunches []bunchOfTr
return selectedTransactions, accumulatedGas
}

// Note (future micro-optimization): we can merge "detectSkippableSender()" and "detectSkippableTransaction()" into a single function,
// any share the result of "sessionWrapper.getNonce()".
func detectSkippableSender(sessionWrapper *selectionSessionWrapper, item *transactionsHeapItem) bool {
nonce := sessionWrapper.getNonce(item.sender)

Expand Down
3 changes: 1 addition & 2 deletions txcache/selectionSessionWrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ func (sessionWrapper *selectionSessionWrapper) getAccountRecord(address []byte)
}

func (sessionWrapper *selectionSessionWrapper) getNonce(address []byte) uint64 {
record := sessionWrapper.getAccountRecord(address)
return record.initialNonce
return sessionWrapper.getAccountRecord(address).initialNonce
}

func (sessionWrapper *selectionSessionWrapper) accumulateConsumedBalance(tx *WrappedTransaction) {
Expand Down
103 changes: 103 additions & 0 deletions txcache/selectionSessionWrapper_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package txcache

import (
"fmt"
"math/big"
"testing"

"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-storage-go/testscommon/txcachemocks"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -131,3 +133,104 @@ func TestSelectionSessionWrapper_detectWillFeeExceedBalance(t *testing.T) {
})
}

func TestBenchmarkSelectionSessionWrapper_getNonce(t *testing.T) {
sw := core.NewStopWatch()

t.Run("getNonce: numAccounts = 300, numTransactionsPerAccount = 100", func(t *testing.T) {
session := txcachemocks.NewSelectionSessionMock()
sessionWrapper := newSelectionSessionWrapper(session)

numAccounts := 300
numTransactions := 100
// See "detectSkippableSender()" and "detectSkippableTransaction()".
numCallsGetNoncePerTransaction := 2
numCallsGetNoncePerAccount := numTransactions * numCallsGetNoncePerTransaction

for i := 0; i < numAccounts; i++ {
session.SetNonce(randomAddresses.getItem(i), uint64(i))
}

sw.Start(t.Name())

for i := 0; i < numAccounts; i++ {
for j := 0; j < numCallsGetNoncePerAccount; j++ {
_ = sessionWrapper.getNonce(randomAddresses.getItem(i))
}
}

sw.Stop(t.Name())

require.Equal(t, numAccounts, session.NumCallsGetAccountState)
})

t.Run("getNonce: numAccounts = 10_000, numTransactionsPerAccount = 3", func(t *testing.T) {
session := txcachemocks.NewSelectionSessionMock()
sessionWrapper := newSelectionSessionWrapper(session)

numAccounts := 10_000
numTransactions := 3
// See "detectSkippableSender()" and "detectSkippableTransaction()".
numCallsGetNoncePerTransaction := 2
numCallsGetNoncePerAccount := numTransactions * numCallsGetNoncePerTransaction

for i := 0; i < numAccounts; i++ {
session.SetNonce(randomAddresses.getItem(i), uint64(i))
}

sw.Start(t.Name())

for i := 0; i < numAccounts; i++ {
for j := 0; j < numCallsGetNoncePerAccount; j++ {
_ = sessionWrapper.getNonce(randomAddresses.getItem(i))
}
}

sw.Stop(t.Name())

require.Equal(t, numAccounts, session.NumCallsGetAccountState)
})

t.Run("getNonce: numAccounts = 30_000, numTransactionsPerAccount = 1", func(t *testing.T) {
session := txcachemocks.NewSelectionSessionMock()
sessionWrapper := newSelectionSessionWrapper(session)

numAccounts := 30_000
numTransactions := 1
// See "detectSkippableSender()" and "detectSkippableTransaction()".
numCallsGetNoncePerTransaction := 2
numCallsGetNoncePerAccount := numTransactions * numCallsGetNoncePerTransaction

for i := 0; i < numAccounts; i++ {
session.SetNonce(randomAddresses.getItem(i), uint64(i))
}

sw.Start(t.Name())

for i := 0; i < numAccounts; i++ {
for j := 0; j < numCallsGetNoncePerAccount; j++ {
_ = sessionWrapper.getNonce(randomAddresses.getItem(i))
}
}

sw.Stop(t.Name())

require.Equal(t, numAccounts, session.NumCallsGetAccountState)
})

for name, measurement := range sw.GetMeasurementsMap() {
fmt.Printf("%fs (%s)\n", measurement, name)
}

// (1)
// Vendor ID: GenuineIntel
// Model name: 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
// CPU family: 6
// Model: 140
// Thread(s) per core: 2
// Core(s) per socket: 4
//
// Session wrapper operations should have a negligible impact on the performance!
// 0.000826s (TestBenchmarkSelectionSessionWrapper_queriesBreakdown/getNonce:_numAccounts_=_300,_numTransactionsPerAccount_=_100)
// 0.003263s (TestBenchmarkSelectionSessionWrapper_queriesBreakdown/getNonce:_numAccounts_=_10_000,_numTransactionsPerAccount_=_3)
// 0.010291s (TestBenchmarkSelectionSessionWrapper_queriesBreakdown/getNonce:_numAccounts_=_30_000,_numTransactionsPerAccount_=_1)
}
16 changes: 8 additions & 8 deletions txcache/selection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,10 @@ func TestBenchmarkTxCache_selectTransactionsFromBunches(t *testing.T) {
// Thread(s) per core: 2
// Core(s) per socket: 4
//
// 0.057519s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_1000,_numTransactions_=_1000)
// 0.048023s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_10000,_numTransactions_=_100)
// 0.289515s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_100000,_numTransactions_=_3)
// 0.460242s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_300000,_numTransactions_=_1)
// 0.074999s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_1000,_numTransactions_=_1000)
// 0.059256s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_10000,_numTransactions_=_100)
// 0.389317s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_100000,_numTransactions_=_3)
// 0.498457s (TestBenchmarkTxCache_selectTransactionsFromBunches/numSenders_=_300000,_numTransactions_=_1)
}

func TestTxCache_selectTransactionsFromBunches_loopBreaks_whenTakesTooLong(t *testing.T) {
Expand Down Expand Up @@ -572,8 +572,8 @@ func TestBenchmarkTxCache_doSelectTransactions(t *testing.T) {
// Thread(s) per core: 2
// Core(s) per socket: 4
//
// 0.042209s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_10000,_numTransactions_=_100,_maxNum_=_30_000)
// 0.055784s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_50000,_numTransactions_=_2,_maxNum_=_30_000)
// 0.078637s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_100000,_numTransactions_=_1,_maxNum_=_30_000)
// 0.222669s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_300000,_numTransactions_=_1,_maxNum_=_30_000)
// 0.048709s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_10000,_numTransactions_=_100,_maxNum_=_30_000)
// 0.076177s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_50000,_numTransactions_=_2,_maxNum_=_30_000)
// 0.104399s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_100000,_numTransactions_=_1,_maxNum_=_30_000)
// 0.319060s (TestBenchmarkTxCache_doSelectTransactions/numSenders_=_300000,_numTransactions_=_1,_maxNum_=_30_000)
}
33 changes: 33 additions & 0 deletions txcache/testutils_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package txcache

import (
cryptoRand "crypto/rand"
"encoding/binary"
"math"
"math/big"
"math/rand"
"sync"
Expand All @@ -16,12 +18,43 @@ const oneBillion = oneMilion * 1000
const oneQuintillion = 1_000_000_000_000_000_000
const estimatedSizeOfBoundedTxFields = uint64(128)
const hashLength = 32
const addressLength = 32

var oneQuintillionBig = big.NewInt(oneQuintillion)

// The GitHub Actions runners are (extremely) slow.
const selectionLoopMaximumDuration = 30 * time.Second

var randomHashes = newRandomData(math.MaxUint16, hashLength)
var randomAddresses = newRandomData(math.MaxUint16, addressLength)

type randomData struct {
randomBytes []byte
numItems int
itemSize int
}

func newRandomData(numItems int, itemSize int) *randomData {
randomBytes := make([]byte, numItems*itemSize)

_, err := cryptoRand.Read(randomBytes)
if err != nil {
panic(err)
}

return &randomData{
randomBytes: randomBytes,
numItems: numItems,
itemSize: itemSize,
}
}

func (data *randomData) getItem(index int) []byte {
start := index * data.itemSize
end := start + data.itemSize
return data.randomBytes[start:end]
}

func (cache *TxCache) areInternalMapsConsistent() bool {
internalMapByHash := cache.txByHash
internalMapBySender := cache.txListBySender
Expand Down
16 changes: 6 additions & 10 deletions txcache/txCache_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package txcache

import (
"crypto/rand"
"errors"
"fmt"
"math"
Expand Down Expand Up @@ -528,9 +527,6 @@ func TestBenchmarkTxCache_addManyTransactionsWithSameNonce(t *testing.T) {
}

host := txcachemocks.NewMempoolHostMock()
randomBytes := make([]byte, math.MaxUint16*hashLength)
_, err := rand.Read(randomBytes)
require.Nil(t, err)

sw := core.NewStopWatch()

Expand All @@ -543,7 +539,7 @@ func TestBenchmarkTxCache_addManyTransactionsWithSameNonce(t *testing.T) {
sw.Start(t.Name())

for i := 0; i < numTransactions; i++ {
cache.AddTx(createTx(randomBytes[i*hashLength:(i+1)*hashLength], "alice", 42).withGasPrice(oneBillion + uint64(i)))
cache.AddTx(createTx(randomHashes.getItem(i), "alice", 42).withGasPrice(oneBillion + uint64(i)))
}

sw.Stop(t.Name())
Expand All @@ -560,7 +556,7 @@ func TestBenchmarkTxCache_addManyTransactionsWithSameNonce(t *testing.T) {
sw.Start(t.Name())

for i := 0; i < numTransactions; i++ {
cache.AddTx(createTx(randomBytes[i*hashLength:(i+1)*hashLength], "alice", 42).withGasPrice(oneBillion + uint64(i)))
cache.AddTx(createTx(randomHashes.getItem(i), "alice", 42).withGasPrice(oneBillion + uint64(i)))
}

sw.Stop(t.Name())
Expand All @@ -577,7 +573,7 @@ func TestBenchmarkTxCache_addManyTransactionsWithSameNonce(t *testing.T) {
sw.Start(t.Name())

for i := 0; i < numTransactions; i++ {
cache.AddTx(createTx(randomBytes[i*hashLength:(i+1)*hashLength], "alice", 42).withGasPrice(oneBillion + uint64(i)))
cache.AddTx(createTx(randomHashes.getItem(i), "alice", 42).withGasPrice(oneBillion + uint64(i)))
}

sw.Stop(t.Name())
Expand All @@ -597,9 +593,9 @@ func TestBenchmarkTxCache_addManyTransactionsWithSameNonce(t *testing.T) {
// Thread(s) per core: 2
// Core(s) per socket: 4
//
// 0.000117s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_100)
// 0.003117s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_1000)
// 0.056481s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_5_000)
// 0.000120s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_100_(worst_case))
// 0.002821s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_1000_(worst_case))
// 0.062260s (TestBenchmarkTxCache_addManyTransactionsWithSameNonce/numTransactions_=_5_000_(worst_case))
}

func newUnconstrainedCacheToTest() *TxCache {
Expand Down

0 comments on commit 7ae6171

Please sign in to comment.