github.com/klaytn/klaytn@v1.12.1/tests/pregenerated_data_execution_test.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "crypto/ecdsa" 21 "fmt" 22 "runtime/pprof" 23 "testing" 24 25 "github.com/klaytn/klaytn/blockchain" 26 "github.com/klaytn/klaytn/blockchain/types" 27 "github.com/klaytn/klaytn/common" 28 ) 29 30 const txPoolSize = 32768 31 32 // BenchmarkDataExecution_Aspen generates the data with Aspen network's database configurations. 33 func BenchmarkDataExecution_Aspen(b *testing.B) { 34 tc := getExecutionTestDefaultTC() 35 tc.testName = "BenchmarkDataExecution_Aspen" 36 tc.originalDataDir = aspen500_orig 37 tc.dbc, tc.levelDBOption = genAspenOptions() 38 39 dataExecutionTest(b, tc) 40 } 41 42 // BenchmarkDataExecution_Baobab generates the data with Baobab network's database configurations. 43 func BenchmarkDataExecution_Baobab(b *testing.B) { 44 tc := getExecutionTestDefaultTC() 45 tc.testName = "BenchmarkDataExecution_Baobab" 46 tc.originalDataDir = baobab500_orig 47 48 tc.dbc, tc.levelDBOption = genBaobabOptions() 49 50 dataExecutionTest(b, tc) 51 } 52 53 // BenchmarkDataExecution_CandidateLevelDB generates the data for main-net's 54 // with candidate configurations, using LevelDB. 55 func BenchmarkDataExecution_CandidateLevelDB(b *testing.B) { 56 tc := getExecutionTestDefaultTC() 57 tc.testName = "BenchmarkDataExecution_CandidateLevelDB" 58 tc.originalDataDir = candidate500LevelDB_orig 59 60 tc.dbc, tc.levelDBOption = genCandidateLevelDBOptions() 61 62 dataExecutionTest(b, tc) 63 } 64 65 // BenchmarkDataExecution_CandidateBadgerDB generates the data for main-net's 66 // with candidate configurations, using BadgerDB. 67 func BenchmarkDataExecution_CandidateBadgerDB(b *testing.B) { 68 tc := getExecutionTestDefaultTC() 69 tc.testName = "BenchmarkDataExecution_CandidateBadgerDB" 70 tc.originalDataDir = candidate500BadgerDB_orig 71 72 tc.dbc, tc.levelDBOption = genCandidateBadgerDBOptions() 73 74 dataExecutionTest(b, tc) 75 } 76 77 // BenchmarkDataExecution_Baobab_ControlGroup generates the data with Baobab network's database configurations. 78 // To work as a control group, it only generates 10,000 accounts. 79 func BenchmarkDataExecution_Baobab_ControlGroup(b *testing.B) { 80 tc := getExecutionTestDefaultTC() 81 tc.testName = "BenchmarkDataExecution_Baobab_ControlGroup" 82 tc.originalDataDir = baobab1_orig 83 84 tc.dbc, tc.levelDBOption = genBaobabOptions() 85 86 // ControlGroup specific setting 87 tc.numReceiversPerRun = 10000 88 89 dataExecutionTest(b, tc) 90 } 91 92 // Static variables, not to read same addresses and keys from files repeatedly. 93 // If there are saved addresses and keys and the given numReceiversPerRun and testDataDir 94 // match with saved ones, it will reuse saved addresses and keys. 95 var savedAddresses []*common.Address = nil 96 97 var ( 98 savedKeys []*ecdsa.PrivateKey = nil 99 savedNumReceiversPerRun int 100 savedTestDataDir string 101 ) 102 103 // dataExecutionTest is to check the performance of Klaytn with pre-generated data. 104 // It generates warmUpTxs and executionTxs first, and then initialize blockchain and database to 105 // remove any effects caused by generating transactions. And then it executes warmUpTxs and executionTxs. 106 // To run the test, original data directory should be located at "$GOPATH/src/github.com/klaytn/" 107 func dataExecutionTest(b *testing.B, tc *preGeneratedTC) { 108 testDataDir, profileFile, err := setUpTest(tc) 109 if err != nil { 110 b.Fatal(err) 111 } 112 113 /////////////////////////////////////////////////////////////////////////////////// 114 /// Tx Generation Process. Generate warmUpTxs and executionTxs in this phase. /// 115 /////////////////////////////////////////////////////////////////////////////////// 116 117 // activeAddrs is used for both sender and receiver. 118 // len(activeAddrs) = tc.numReceiversPerRun 119 if savedAddresses == nil || savedKeys == nil || tc.numReceiversPerRun != savedNumReceiversPerRun || testDataDir != savedTestDataDir { 120 fmt.Println("Start reading addresses from files", "testDataDir", testDataDir, "numReceiversPerRun", tc.numReceiversPerRun) 121 savedAddresses, savedKeys, err = getAddrsAndKeysFromFile(tc.numReceiversPerRun, testDataDir, 0, tc.filePicker) 122 savedNumReceiversPerRun = tc.numReceiversPerRun 123 savedTestDataDir = testDataDir 124 if err != nil { 125 b.Fatal(err) 126 } 127 fmt.Println("End reading addresses from files") 128 } else { 129 fmt.Println("Reuse previously saved addresses and keys", "len(addrs)", len(savedAddresses), "len(keys)", len(savedKeys)) 130 } 131 132 activeAddrs, activeKeys := savedAddresses, savedKeys 133 134 bcData, err := NewBCDataForPreGeneratedTest(testDataDir, tc) 135 if err != nil { 136 b.Fatal(err) 137 } 138 139 // Generate two different list of transactions, warmUpTxs and executionTxs 140 // warmUpTxs is to activate caching. 141 // executionTxs is to measure the performance of test after caching. 142 signer := types.MakeSigner(bcData.bc.Config(), bcData.bc.CurrentHeader().Number) 143 stateDB, err := bcData.bc.State() 144 if err != nil { 145 b.Fatal(err) 146 } 147 148 // len(warmUpTxs) = tc.numReceiversPerRun 149 warmUpTxs, nonceMap, err := makeTxsWithStateDB(false, stateDB, activeAddrs, activeKeys, activeAddrs, signer, tc.numReceiversPerRun, sequentialIndex) 150 if err != nil { 151 b.Fatal(err) 152 } 153 154 // len(executionTxs) = tc.numTxsPerGen 155 executionTxs, _, err := makeTxsWithNonceMap(false, nonceMap, activeAddrs, activeKeys, activeAddrs, signer, tc.numTxsPerGen, randomIndex) 156 if err != nil { 157 b.Fatal(err) 158 } 159 160 fmt.Println("len(warmUpTxs)", len(warmUpTxs), "len(executionTxs)", len(executionTxs)) 161 162 bcData.bc.Stop() 163 bcData.db.Close() 164 165 ///////////////////////////////////////////////////////////////////////////////////////////// 166 /// Tx Execution Process. Shutdown and initialize DB to execute txs in fresh condition. /// 167 ///////////////////////////////////////////////////////////////////////////////////////////// 168 fmt.Println("Re-setting up test data dir to make database to initial condition.") 169 testDataDir, err = setupTestDir(tc.originalDataDir, tc.isGenerateTest) 170 if err != nil { 171 b.Fatalf("err: %v, dir: %v", err, testDataDir) 172 } 173 174 bcData, err = NewBCDataForPreGeneratedTest(testDataDir, tc) 175 if err != nil { 176 b.Fatal(err) 177 } 178 defer bcData.db.Close() 179 defer bcData.bc.Stop() 180 181 signer = types.MakeSigner(bcData.bc.Config(), bcData.bc.CurrentHeader().Number) 182 stateDB, err = bcData.bc.State() 183 if err != nil { 184 b.Fatal(err) 185 } 186 187 fmt.Println("Call AsMessageWithAccountKeyPicker for warmUpTxs") 188 for _, tx := range warmUpTxs { 189 if _, err = tx.AsMessageWithAccountKeyPicker(signer, stateDB, bcData.bc.CurrentBlock().NumberU64()); err != nil { 190 b.Fatal(err) 191 } 192 } 193 194 fmt.Println("Call AsMessageWithAccountKeyPicker for executionTxs") 195 for _, tx := range executionTxs { 196 if _, err = tx.AsMessageWithAccountKeyPicker(signer, stateDB, bcData.bc.CurrentBlock().NumberU64()); err != nil { 197 b.Fatal(err) 198 } 199 } 200 201 txPool := makeTxPool(bcData, txPoolSize) 202 203 // Run warmUpTxs. 204 fmt.Println("Start warming-up phase") 205 if err := executeTxs(bcData, txPool, warmUpTxs); err != nil { 206 b.Fatal(err) 207 } 208 fmt.Println("End warming-up phase. Start execution phase.") 209 // Run executionTxs and measure the execution time and profiling. 210 // Start timer and profiler from here. 211 b.ResetTimer() 212 b.StartTimer() 213 defer b.StopTimer() 214 pprof.StartCPUProfile(profileFile) 215 defer pprof.StopCPUProfile() 216 217 if err := executeTxs(bcData, txPool, executionTxs); err != nil { 218 b.Fatal(err) 219 } 220 } 221 222 // executeTxs repeats pushing and executing certain number of transactions until 223 // there is no transaction left. 224 func executeTxs(bcData *BCData, txPool *blockchain.TxPool, txs types.Transactions) error { 225 for i := 0; i < len(txs); i += txPoolSize { 226 end := i + txPoolSize 227 if end > len(txs) { 228 end = len(txs) 229 } 230 txPool.AddRemotes(txs[i:end]) 231 for { 232 if err := bcData.GenABlockWithTxPoolWithoutAccountMap(txPool); err != nil { 233 if err == errEmptyPending { 234 break 235 } 236 return err 237 } 238 } 239 } 240 return nil 241 } 242 243 // getExecutionTestDefaultTC returns default TC of data execution tests. 244 func getExecutionTestDefaultTC() *preGeneratedTC { 245 numActiveAccounts := 100 * 10000 246 numExecPhaseTxs := txPoolSize * 10 247 248 return &preGeneratedTC{ 249 isGenerateTest: false, 250 numReceiversPerRun: numActiveAccounts, // number of accounts used for warming-up phase, which means "active accounts" 251 numTxsPerGen: numExecPhaseTxs, // number of transactions executed during execution phase 252 numTotalSenders: 10000, 253 filePicker: sequentialIndex, 254 addrPicker: sequentialIndex, 255 cacheConfig: defaultCacheConfig(), 256 } 257 }