github.com/koko1123/flow-go-1@v0.29.6/engine/execution/computation/manager_benchmark_test.go (about) 1 package computation 2 3 import ( 4 "context" 5 "fmt" 6 "math/rand" 7 "testing" 8 "time" 9 10 "github.com/ipfs/go-datastore" 11 dssync "github.com/ipfs/go-datastore/sync" 12 blockstore "github.com/ipfs/go-ipfs-blockstore" 13 "github.com/onflow/cadence/runtime" 14 "github.com/rs/zerolog" 15 "github.com/stretchr/testify/mock" 16 "github.com/stretchr/testify/require" 17 18 "github.com/koko1123/flow-go-1/engine/execution/computation/committer" 19 "github.com/koko1123/flow-go-1/engine/execution/computation/computer" 20 "github.com/koko1123/flow-go-1/engine/execution/state/delta" 21 "github.com/koko1123/flow-go-1/engine/execution/testutil" 22 "github.com/koko1123/flow-go-1/fvm" 23 "github.com/koko1123/flow-go-1/fvm/derived" 24 reusableRuntime "github.com/koko1123/flow-go-1/fvm/runtime" 25 "github.com/koko1123/flow-go-1/fvm/state" 26 "github.com/koko1123/flow-go-1/model/flow" 27 "github.com/koko1123/flow-go-1/module/executiondatasync/execution_data" 28 exedataprovider "github.com/koko1123/flow-go-1/module/executiondatasync/provider" 29 mocktracker "github.com/koko1123/flow-go-1/module/executiondatasync/tracker/mock" 30 "github.com/koko1123/flow-go-1/module/mempool/entity" 31 "github.com/koko1123/flow-go-1/module/metrics" 32 module "github.com/koko1123/flow-go-1/module/mock" 33 requesterunit "github.com/koko1123/flow-go-1/module/state_synchronization/requester/unittest" 34 "github.com/koko1123/flow-go-1/module/trace" 35 "github.com/koko1123/flow-go-1/utils/unittest" 36 ) 37 38 type testAccount struct { 39 address flow.Address 40 privateKey flow.AccountPrivateKey 41 } 42 43 type testAccounts struct { 44 accounts []testAccount 45 seq uint64 46 } 47 48 func createAccounts(b *testing.B, vm fvm.VM, ledger state.View, num int) *testAccounts { 49 privateKeys, err := testutil.GenerateAccountPrivateKeys(num) 50 require.NoError(b, err) 51 52 addresses, err := testutil.CreateAccounts( 53 vm, 54 ledger, 55 derived.NewEmptyDerivedBlockData(), 56 privateKeys, 57 chain) 58 require.NoError(b, err) 59 60 accs := &testAccounts{ 61 accounts: make([]testAccount, num), 62 } 63 for i := 0; i < num; i++ { 64 accs.accounts[i] = testAccount{ 65 address: addresses[i], 66 privateKey: privateKeys[i], 67 } 68 } 69 return accs 70 } 71 72 func mustFundAccounts( 73 b *testing.B, 74 vm fvm.VM, 75 ledger state.View, 76 execCtx fvm.Context, 77 accs *testAccounts, 78 ) { 79 derivedBlockData := derived.NewEmptyDerivedBlockData() 80 execCtx = fvm.NewContextFromParent( 81 execCtx, 82 fvm.WithDerivedBlockData(derivedBlockData)) 83 84 var err error 85 for _, acc := range accs.accounts { 86 transferTx := testutil.CreateTokenTransferTransaction(chain, 1_000_000, acc.address, chain.ServiceAddress()) 87 err = testutil.SignTransactionAsServiceAccount(transferTx, accs.seq, chain) 88 require.NoError(b, err) 89 accs.seq++ 90 91 tx := fvm.Transaction( 92 transferTx, 93 derivedBlockData.NextTxIndexForTestingOnly()) 94 err = vm.Run(execCtx, tx, ledger) 95 require.NoError(b, err) 96 require.NoError(b, tx.Err) 97 } 98 } 99 100 func BenchmarkComputeBlock(b *testing.B) { 101 b.StopTimer() 102 103 tracer, err := trace.NewTracer(zerolog.Nop(), "", "", 4) 104 require.NoError(b, err) 105 106 vm := fvm.NewVirtualMachine() 107 108 chain := flow.Emulator.Chain() 109 execCtx := fvm.NewContext( 110 fvm.WithChain(chain), 111 fvm.WithAccountStorageLimit(true), 112 fvm.WithTransactionFeesEnabled(true), 113 fvm.WithTracer(tracer), 114 fvm.WithReusableCadenceRuntimePool( 115 reusableRuntime.NewReusableCadenceRuntimePool( 116 ReusableCadenceRuntimePoolSize, 117 runtime.Config{})), 118 ) 119 ledger := testutil.RootBootstrappedLedger( 120 vm, 121 execCtx, 122 fvm.WithAccountCreationFee(fvm.DefaultAccountCreationFee), 123 fvm.WithMinimumStorageReservation(fvm.DefaultMinimumStorageReservation), 124 fvm.WithTransactionFee(fvm.DefaultTransactionFees), 125 fvm.WithStorageMBPerFLOW(fvm.DefaultStorageMBPerFLOW), 126 ) 127 accs := createAccounts(b, vm, ledger, 1000) 128 mustFundAccounts(b, vm, ledger, execCtx, accs) 129 130 me := new(module.Local) 131 me.On("NodeID").Return(flow.ZeroID) 132 me.On("SignFunc", mock.Anything, mock.Anything, mock.Anything). 133 Return(nil, nil) 134 135 bservice := requesterunit.MockBlobService(blockstore.NewBlockstore(dssync.MutexWrap(datastore.NewMapDatastore()))) 136 trackerStorage := mocktracker.NewMockStorage() 137 138 prov := exedataprovider.NewProvider( 139 zerolog.Nop(), 140 metrics.NewNoopCollector(), 141 execution_data.DefaultSerializer, 142 bservice, 143 trackerStorage, 144 ) 145 146 // TODO(rbtz): add real ledger 147 blockComputer, err := computer.NewBlockComputer( 148 vm, 149 execCtx, 150 metrics.NewNoopCollector(), 151 tracer, 152 zerolog.Nop(), 153 committer.NewNoopViewCommitter(), 154 me, 155 prov) 156 require.NoError(b, err) 157 158 derivedChainData, err := derived.NewDerivedChainData( 159 derived.DefaultDerivedDataCacheSize) 160 require.NoError(b, err) 161 162 engine := &Manager{ 163 blockComputer: blockComputer, 164 tracer: tracer, 165 me: me, 166 derivedChainData: derivedChainData, 167 } 168 169 view := delta.NewView(ledger.Get) 170 blockView := view.NewChild() 171 172 b.SetParallelism(1) 173 174 parentBlock := &flow.Block{ 175 Header: &flow.Header{}, 176 Payload: &flow.Payload{}, 177 } 178 179 const ( 180 cols = 16 181 txes = 128 182 ) 183 184 b.Run(fmt.Sprintf("%d/cols/%d/txes", cols, txes), func(b *testing.B) { 185 b.StopTimer() 186 b.ResetTimer() 187 188 var elapsed time.Duration 189 for i := 0; i < b.N; i++ { 190 executableBlock := createBlock(b, parentBlock, accs, cols, txes) 191 parentBlock = executableBlock.Block 192 193 b.StartTimer() 194 start := time.Now() 195 res, err := engine.ComputeBlock(context.Background(), executableBlock, blockView) 196 elapsed += time.Since(start) 197 b.StopTimer() 198 199 require.NoError(b, err) 200 for j, r := range res.TransactionResults { 201 // skip system transactions 202 if j >= cols*txes { 203 break 204 } 205 require.Emptyf(b, r.ErrorMessage, "Transaction %d failed", j) 206 } 207 } 208 totalTxes := int64(cols) * int64(txes) * int64(b.N) 209 b.ReportMetric(float64(elapsed.Nanoseconds()/totalTxes/int64(time.Microsecond)), "us/tx") 210 }) 211 } 212 213 func createBlock(b *testing.B, parentBlock *flow.Block, accs *testAccounts, colNum int, txNum int) *entity.ExecutableBlock { 214 completeCollections := make(map[flow.Identifier]*entity.CompleteCollection, colNum) 215 collections := make([]*flow.Collection, colNum) 216 guarantees := make([]*flow.CollectionGuarantee, colNum) 217 218 for c := 0; c < colNum; c++ { 219 transactions := make([]*flow.TransactionBody, txNum) 220 for t := 0; t < txNum; t++ { 221 transactions[t] = createTokenTransferTransaction(b, accs) 222 } 223 224 collection := &flow.Collection{Transactions: transactions} 225 guarantee := &flow.CollectionGuarantee{CollectionID: collection.ID()} 226 227 collections[c] = collection 228 guarantees[c] = guarantee 229 completeCollections[guarantee.ID()] = &entity.CompleteCollection{ 230 Guarantee: guarantee, 231 Transactions: transactions, 232 } 233 } 234 235 block := flow.Block{ 236 Header: &flow.Header{ 237 ParentID: parentBlock.ID(), 238 View: parentBlock.Header.Height + 1, 239 }, 240 Payload: &flow.Payload{ 241 Guarantees: guarantees, 242 }, 243 } 244 245 return &entity.ExecutableBlock{ 246 Block: &block, 247 CompleteCollections: completeCollections, 248 StartState: unittest.StateCommitmentPointerFixture(), 249 } 250 } 251 252 func createTokenTransferTransaction(b *testing.B, accs *testAccounts) *flow.TransactionBody { 253 var err error 254 255 rnd := rand.Intn(len(accs.accounts)) 256 src := accs.accounts[rnd] 257 dst := accs.accounts[(rnd+1)%len(accs.accounts)] 258 259 tx := testutil.CreateTokenTransferTransaction(chain, 1, dst.address, src.address) 260 tx.SetProposalKey(chain.ServiceAddress(), 0, accs.seq). 261 SetGasLimit(1000). 262 SetPayer(chain.ServiceAddress()) 263 accs.seq++ 264 265 err = testutil.SignPayload(tx, src.address, src.privateKey) 266 require.NoError(b, err) 267 268 err = testutil.SignEnvelope(tx, chain.ServiceAddress(), unittest.ServiceAccountPrivateKey) 269 require.NoError(b, err) 270 271 return tx 272 }