Merge pull request #183 from tendermint/feature/121-add-benchmarks
Add benchmark for abci app
This commit is contained in:
commit
4bf711f529
|
@ -0,0 +1,199 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
wire "github.com/tendermint/go-wire"
|
||||||
|
eyesApp "github.com/tendermint/merkleeyes/app"
|
||||||
|
eyes "github.com/tendermint/merkleeyes/client"
|
||||||
|
cmn "github.com/tendermint/tmlibs/common"
|
||||||
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
"github.com/tendermint/basecoin/app"
|
||||||
|
"github.com/tendermint/basecoin/modules/auth"
|
||||||
|
"github.com/tendermint/basecoin/modules/base"
|
||||||
|
"github.com/tendermint/basecoin/modules/coin"
|
||||||
|
"github.com/tendermint/basecoin/modules/fee"
|
||||||
|
"github.com/tendermint/basecoin/modules/nonce"
|
||||||
|
"github.com/tendermint/basecoin/modules/roles"
|
||||||
|
"github.com/tendermint/basecoin/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BenchApp struct {
|
||||||
|
App *app.Basecoin
|
||||||
|
Accounts []*coin.AccountWithKey
|
||||||
|
ChainID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultHandler - placeholder to just handle sendtx
|
||||||
|
func DefaultHandler(feeDenom string) basecoin.Handler {
|
||||||
|
// use the default stack
|
||||||
|
c := coin.NewHandler()
|
||||||
|
r := roles.NewHandler()
|
||||||
|
d := stack.NewDispatcher(
|
||||||
|
stack.WrapHandler(c),
|
||||||
|
stack.WrapHandler(r),
|
||||||
|
)
|
||||||
|
return stack.New(
|
||||||
|
base.Logger{},
|
||||||
|
stack.Recovery{},
|
||||||
|
auth.Signatures{},
|
||||||
|
base.Chain{},
|
||||||
|
nonce.ReplayCheck{},
|
||||||
|
roles.NewMiddleware(),
|
||||||
|
fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank),
|
||||||
|
).Use(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBenchApp(h basecoin.Handler, chainID string, n int,
|
||||||
|
persist bool) BenchApp {
|
||||||
|
|
||||||
|
logger := log.NewNopLogger()
|
||||||
|
// logger := log.NewFilter(log.NewTMLogger(os.Stdout), log.AllowError())
|
||||||
|
// logger = log.NewTracingLogger(logger)
|
||||||
|
|
||||||
|
// TODO: disk writing
|
||||||
|
var eyesCli *eyes.Client
|
||||||
|
if persist {
|
||||||
|
tmpDir, _ := ioutil.TempDir("", "bc-app-benchmark")
|
||||||
|
eyesCli = eyes.NewLocalClient(tmpDir, 500)
|
||||||
|
} else {
|
||||||
|
eyesCli = eyes.NewLocalClient("", 0)
|
||||||
|
}
|
||||||
|
eyesApp.SetLogger(logger.With("module", "merkle"))
|
||||||
|
|
||||||
|
app := app.NewBasecoin(
|
||||||
|
h,
|
||||||
|
eyesCli,
|
||||||
|
logger.With("module", "app"),
|
||||||
|
)
|
||||||
|
res := app.SetOption("base/chain_id", chainID)
|
||||||
|
if res != "Success" {
|
||||||
|
panic("cannot set chain")
|
||||||
|
}
|
||||||
|
|
||||||
|
// make keys
|
||||||
|
money := coin.Coins{{"mycoin", 1234567890}}
|
||||||
|
accts := make([]*coin.AccountWithKey, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
accts[i] = coin.NewAccountWithKey(money)
|
||||||
|
res := app.SetOption("coin/account", accts[i].MakeOption())
|
||||||
|
if res != "Success" {
|
||||||
|
panic("can't set account")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BenchApp{
|
||||||
|
App: app,
|
||||||
|
Accounts: accts,
|
||||||
|
ChainID: chainID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a random tx...
|
||||||
|
func (b BenchApp) makeTx(useFee bool) []byte {
|
||||||
|
n := len(b.Accounts)
|
||||||
|
sender := b.Accounts[cmn.RandInt()%n]
|
||||||
|
recipient := b.Accounts[cmn.RandInt()%n]
|
||||||
|
amount := coin.Coins{{"mycoin", 123}}
|
||||||
|
tx := coin.NewSendOneTx(sender.Actor(), recipient.Actor(), amount)
|
||||||
|
if useFee {
|
||||||
|
toll := coin.Coin{"mycoin", 2}
|
||||||
|
tx = fee.NewFee(tx, toll, sender.Actor())
|
||||||
|
}
|
||||||
|
sequence := sender.NextSequence()
|
||||||
|
tx = nonce.NewTx(sequence, []basecoin.Actor{sender.Actor()}, tx)
|
||||||
|
tx = base.NewChainTx(b.ChainID, 0, tx)
|
||||||
|
stx := auth.NewMulti(tx)
|
||||||
|
auth.Sign(stx, sender.Key)
|
||||||
|
res := wire.BinaryBytes(stx.Wrap())
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMakeTx(b *testing.B) {
|
||||||
|
h := DefaultHandler("mycoin")
|
||||||
|
app := NewBenchApp(h, "bench-chain", 10, false)
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 1; i <= b.N; i++ {
|
||||||
|
txBytes := app.makeTx(true)
|
||||||
|
if len(txBytes) < 2 {
|
||||||
|
panic("cannot commit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func benchmarkTransfers(b *testing.B, app BenchApp, blockSize int, useFee bool) {
|
||||||
|
// prepare txs
|
||||||
|
txs := make([][]byte, b.N)
|
||||||
|
for i := 1; i <= b.N; i++ {
|
||||||
|
txBytes := app.makeTx(useFee)
|
||||||
|
if len(txBytes) < 2 {
|
||||||
|
panic("cannot make bytes")
|
||||||
|
}
|
||||||
|
txs[i-1] = txBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
|
||||||
|
for i := 1; i <= b.N; i++ {
|
||||||
|
res := app.App.DeliverTx(txs[i-1])
|
||||||
|
if res.IsErr() {
|
||||||
|
panic(res.Error())
|
||||||
|
}
|
||||||
|
if i%blockSize == 0 {
|
||||||
|
res := app.App.Commit()
|
||||||
|
if res.IsErr() {
|
||||||
|
panic("cannot commit")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSimpleTransfer(b *testing.B) {
|
||||||
|
benchmarks := []struct {
|
||||||
|
accounts int
|
||||||
|
blockSize int
|
||||||
|
useFee bool
|
||||||
|
toDisk bool
|
||||||
|
}{
|
||||||
|
{100, 10, false, false},
|
||||||
|
{100, 10, true, false},
|
||||||
|
{100, 200, false, false},
|
||||||
|
{100, 200, true, false},
|
||||||
|
{10000, 10, false, false},
|
||||||
|
{10000, 10, true, false},
|
||||||
|
{10000, 200, false, false},
|
||||||
|
{10000, 200, true, false},
|
||||||
|
{100, 10, false, true},
|
||||||
|
{100, 10, true, true},
|
||||||
|
{100, 200, false, true},
|
||||||
|
{100, 200, true, true},
|
||||||
|
{10000, 10, false, true},
|
||||||
|
{10000, 10, true, true},
|
||||||
|
{10000, 200, false, true},
|
||||||
|
{10000, 200, true, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bb := range benchmarks {
|
||||||
|
prefix := fmt.Sprintf("%d-%d", bb.accounts, bb.blockSize)
|
||||||
|
if bb.useFee {
|
||||||
|
prefix += "-fee"
|
||||||
|
} else {
|
||||||
|
prefix += "-nofee"
|
||||||
|
}
|
||||||
|
if bb.toDisk {
|
||||||
|
prefix += "-persist"
|
||||||
|
} else {
|
||||||
|
prefix += "-memdb"
|
||||||
|
}
|
||||||
|
|
||||||
|
h := DefaultHandler("mycoin")
|
||||||
|
app := NewBenchApp(h, "bench-chain", bb.accounts, bb.toDisk)
|
||||||
|
b.Run(prefix, func(sub *testing.B) {
|
||||||
|
benchmarkTransfers(sub, app, bb.blockSize, bb.useFee)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,8 @@ import (
|
||||||
// AccountWithKey is a helper for tests, that includes and account
|
// AccountWithKey is a helper for tests, that includes and account
|
||||||
// along with the private key to access it.
|
// along with the private key to access it.
|
||||||
type AccountWithKey struct {
|
type AccountWithKey struct {
|
||||||
Key crypto.PrivKey
|
Key crypto.PrivKey
|
||||||
|
Sequence uint32
|
||||||
Account
|
Account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +35,12 @@ func (a *AccountWithKey) Actor() basecoin.Actor {
|
||||||
return auth.SigPerm(a.Key.PubKey().Address())
|
return auth.SigPerm(a.Key.PubKey().Address())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NextSequence returns the next sequence to sign with
|
||||||
|
func (a *AccountWithKey) NextSequence() uint32 {
|
||||||
|
a.Sequence++
|
||||||
|
return a.Sequence
|
||||||
|
}
|
||||||
|
|
||||||
// MakeOption returns a string to use with SetOption to initialize this account
|
// MakeOption returns a string to use with SetOption to initialize this account
|
||||||
//
|
//
|
||||||
// This is intended for use in test cases
|
// This is intended for use in test cases
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
package tmsp_test
|
|
||||||
|
|
||||||
// TODO: replace with benchmarker
|
|
||||||
|
|
||||||
// import (
|
|
||||||
// "encoding/json"
|
|
||||||
// "testing"
|
|
||||||
|
|
||||||
// "github.com/stretchr/testify/assert"
|
|
||||||
// "github.com/stretchr/testify/require"
|
|
||||||
// "github.com/tendermint/basecoin/app"
|
|
||||||
// "github.com/tendermint/basecoin/types"
|
|
||||||
// wire "github.com/tendermint/go-wire"
|
|
||||||
// eyescli "github.com/tendermint/merkleeyes/client"
|
|
||||||
// cmn "github.com/tendermint/tmlibs/common"
|
|
||||||
// "github.com/tendermint/tmlibs/log"
|
|
||||||
// )
|
|
||||||
|
|
||||||
// func TestSendTx(t *testing.T) {
|
|
||||||
// eyesCli := eyescli.NewLocalClient("", 0)
|
|
||||||
// chainID := "test_chain_id"
|
|
||||||
// bcApp := app.NewBasecoin(eyesCli, log.TestingLogger().With("module", "app"))
|
|
||||||
// bcApp.SetOption("base/chain_id", chainID)
|
|
||||||
// // t.Log(bcApp.Info())
|
|
||||||
|
|
||||||
// test1PrivAcc := types.PrivAccountFromSecret("test1")
|
|
||||||
// test2PrivAcc := types.PrivAccountFromSecret("test2")
|
|
||||||
|
|
||||||
// // Seed Basecoin with account
|
|
||||||
// test1Acc := test1PrivAcc.Account
|
|
||||||
// test1Acc.Balance = coin.Coins{{"", 1000}}
|
|
||||||
// accOpt, err := json.Marshal(test1Acc)
|
|
||||||
// require.Nil(t, err)
|
|
||||||
// bcApp.SetOption("base/account", string(accOpt))
|
|
||||||
|
|
||||||
// // Construct a SendTx signature
|
|
||||||
// tx := &types.SendTx{
|
|
||||||
// Gas: 0,
|
|
||||||
// Fee: coin.Coin{"", 0},
|
|
||||||
// Inputs: []types.TxInput{
|
|
||||||
// types.NewTxInput(test1PrivAcc.Account.PubKey, coin.Coins{{"", 1}}, 1),
|
|
||||||
// },
|
|
||||||
// Outputs: []types.TxOutput{
|
|
||||||
// types.TxOutput{
|
|
||||||
// Address: test2PrivAcc.Account.PubKey.Address(),
|
|
||||||
// Coins: coin.Coins{{"", 1}},
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Sign request
|
|
||||||
// signBytes := tx.SignBytes(chainID)
|
|
||||||
// // t.Log("Sign bytes: %X\n", signBytes)
|
|
||||||
// sig := test1PrivAcc.Sign(signBytes)
|
|
||||||
// tx.Inputs[0].Signature = sig
|
|
||||||
// // t.Log("Signed TX bytes: %X\n", wire.BinaryBytes(types.TxS{tx}))
|
|
||||||
|
|
||||||
// // Write request
|
|
||||||
// txBytes := wire.BinaryBytes(types.TxS{tx})
|
|
||||||
// res := bcApp.DeliverTx(txBytes)
|
|
||||||
// // t.Log(res)
|
|
||||||
// assert.True(t, res.IsOK(), "Failed: %v", res.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func TestSequence(t *testing.T) {
|
|
||||||
// eyesCli := eyescli.NewLocalClient("", 0)
|
|
||||||
// chainID := "test_chain_id"
|
|
||||||
// bcApp := app.NewBasecoin(eyesCli, log.TestingLogger().With("module", "app"))
|
|
||||||
// bcApp.SetOption("base/chain_id", chainID)
|
|
||||||
// // t.Log(bcApp.Info())
|
|
||||||
|
|
||||||
// // Get the test account
|
|
||||||
// test1PrivAcc := types.PrivAccountFromSecret("test1")
|
|
||||||
// test1Acc := test1PrivAcc.Account
|
|
||||||
// test1Acc.Balance = coin.Coins{{"", 1 << 53}}
|
|
||||||
// accOpt, err := json.Marshal(test1Acc)
|
|
||||||
// require.Nil(t, err)
|
|
||||||
// bcApp.SetOption("base/account", string(accOpt))
|
|
||||||
|
|
||||||
// sequence := int(1)
|
|
||||||
// // Make a bunch of PrivAccounts
|
|
||||||
// privAccounts := types.RandAccounts(1000, 1000000, 0)
|
|
||||||
// privAccountSequences := make(map[string]int)
|
|
||||||
// // Send coins to each account
|
|
||||||
|
|
||||||
// for i := 0; i < len(privAccounts); i++ {
|
|
||||||
// privAccount := privAccounts[i]
|
|
||||||
|
|
||||||
// tx := &types.SendTx{
|
|
||||||
// Gas: 2,
|
|
||||||
// Fee: coin.Coin{"", 2},
|
|
||||||
// Inputs: []types.TxInput{
|
|
||||||
// types.NewTxInput(test1Acc.PubKey, coin.Coins{{"", 1000002}}, sequence),
|
|
||||||
// },
|
|
||||||
// Outputs: []types.TxOutput{
|
|
||||||
// types.TxOutput{
|
|
||||||
// Address: privAccount.Account.PubKey.Address(),
|
|
||||||
// Coins: coin.Coins{{"", 1000000}},
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
// sequence += 1
|
|
||||||
|
|
||||||
// // Sign request
|
|
||||||
// signBytes := tx.SignBytes(chainID)
|
|
||||||
// sig := test1PrivAcc.Sign(signBytes)
|
|
||||||
// tx.Inputs[0].Signature = sig
|
|
||||||
// // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address)
|
|
||||||
|
|
||||||
// // Write request
|
|
||||||
// txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
|
||||||
// res := bcApp.DeliverTx(txBytes)
|
|
||||||
// assert.True(t, res.IsOK(), "DeliverTx error: %v", res.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// res := bcApp.Commit()
|
|
||||||
// assert.True(t, res.IsOK(), "Failed Commit: %v", res.Error())
|
|
||||||
|
|
||||||
// t.Log("-------------------- RANDOM SENDS --------------------")
|
|
||||||
|
|
||||||
// // Now send coins between these accounts
|
|
||||||
// for i := 0; i < 10000; i++ {
|
|
||||||
// randA := cmn.RandInt() % len(privAccounts)
|
|
||||||
// randB := cmn.RandInt() % len(privAccounts)
|
|
||||||
// if randA == randB {
|
|
||||||
// continue
|
|
||||||
// }
|
|
||||||
|
|
||||||
// privAccountA := privAccounts[randA]
|
|
||||||
// privAccountASequence := privAccountSequences[privAccountA.Account.PubKey.KeyString()]
|
|
||||||
// privAccountSequences[privAccountA.Account.PubKey.KeyString()] = privAccountASequence + 1
|
|
||||||
// privAccountB := privAccounts[randB]
|
|
||||||
|
|
||||||
// tx := &types.SendTx{
|
|
||||||
// Gas: 2,
|
|
||||||
// Fee: coin.Coin{"", 2},
|
|
||||||
// Inputs: []types.TxInput{
|
|
||||||
// types.NewTxInput(privAccountA.PubKey, coin.Coins{{"", 3}}, privAccountASequence+1),
|
|
||||||
// },
|
|
||||||
// Outputs: []types.TxOutput{
|
|
||||||
// types.TxOutput{
|
|
||||||
// Address: privAccountB.PubKey.Address(),
|
|
||||||
// Coins: coin.Coins{{"", 1}},
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Sign request
|
|
||||||
// signBytes := tx.SignBytes(chainID)
|
|
||||||
// sig := privAccountA.Sign(signBytes)
|
|
||||||
// tx.Inputs[0].Signature = sig
|
|
||||||
// // t.Log("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address)
|
|
||||||
|
|
||||||
// // Write request
|
|
||||||
// txBytes := wire.BinaryBytes(struct{ types.Tx }{tx})
|
|
||||||
// res := bcApp.DeliverTx(txBytes)
|
|
||||||
// assert.True(t, res.IsOK(), "DeliverTx error: %v", res.Error())
|
|
||||||
// }
|
|
||||||
// }
|
|
Loading…
Reference in New Issue