From e72b20eb7d845968a667506c2ba44e6e0bcdd79c Mon Sep 17 00:00:00 2001 From: Kevin Davis Date: Fri, 28 Feb 2020 17:00:03 -0500 Subject: [PATCH] benchmark account and cdp iteration (#371) * feat: benchmark test for account iteration * feat: add cdp creation and iteration benchmarks * address review comments --- x/cdp/keeper/keeper_bench_test.go | 144 ++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 x/cdp/keeper/keeper_bench_test.go diff --git a/x/cdp/keeper/keeper_bench_test.go b/x/cdp/keeper/keeper_bench_test.go new file mode 100644 index 00000000..20b88c82 --- /dev/null +++ b/x/cdp/keeper/keeper_bench_test.go @@ -0,0 +1,144 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/kava-labs/kava/app" + "github.com/kava-labs/kava/x/cdp" + "github.com/kava-labs/kava/x/cdp/keeper" + abci "github.com/tendermint/tendermint/abci/types" + tmtime "github.com/tendermint/tendermint/types/time" +) + +// saving the result to a module level variable ensures the compiler doesn't optimize the test away +var coinsResult sdk.Coins + +// Note - the iteration benchmarks take a long time to stabilize, to get stable results use: +// go test -benchmem -bench ^(BenchmarkAccountIteration)$ -benchtime 60s -timeout 2h +// go test -benchmem -bench ^(BenchmarkCdpIteration)$ -benchtime 60s -timeout 2h + +func BenchmarkAccountIteration(b *testing.B) { + benchmarks := []struct { + name string + numberAccounts int + coins bool + }{ + {name: "10000 Accounts, No Coins", numberAccounts: 10000, coins: false}, + {name: "100000 Accounts, No Coins", numberAccounts: 100000, coins: false}, + {name: "1000000 Accounts, No Coins", numberAccounts: 1000000, coins: false}, + {name: "10000 Accounts, With Coins", numberAccounts: 10000, coins: true}, + {name: "100000 Accounts, With Coins", numberAccounts: 100000, coins: true}, + {name: "1000000 Accounts, With Coins", numberAccounts: 1000000, coins: true}, + } + coins := sdk.Coins{ + sdk.NewCoin("xrp", sdk.NewInt(1000000000)), + sdk.NewCoin("usdx", sdk.NewInt(1000000000)), + } + + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + ak := tApp.GetAccountKeeper() + tApp.InitializeFromGenesisStates() + for i := 0; i < bm.numberAccounts; i++ { + arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)} + addr := sdk.AccAddress(arr) + acc := ak.NewAccountWithAddress(ctx, addr) + if bm.coins { + acc.SetCoins(coins) + } + ak.SetAccount(ctx, acc) + } + // reset timer ensures we don't count setup time + b.ResetTimer() + for i := 0; i < b.N; i++ { + ak.IterateAccounts(ctx, + func(acc exported.Account) (stop bool) { + coins := acc.GetCoins() + coinsResult = coins + return false + }) + } + }) + } +} + +func createCdps(n int) (app.TestApp, sdk.Context, keeper.Keeper) { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + _, addrs := app.GeneratePrivKeyAddressPairs(n) + coins := []sdk.Coins{} + for i := 0; i < n; i++ { + coins = append(coins, cs(c("btc", 100000000))) + } + authGS := app.NewAuthGenState( + addrs, coins) + tApp.InitializeFromGenesisStates( + authGS, + NewPricefeedGenStateMulti(), + NewCDPGenStateMulti(), + ) + cdpKeeper := tApp.GetCDPKeeper() + for i := 0; i < n; i++ { + err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i], cs(c("usdx", 100000000))) + if err != nil { + panic("failed to create cdp") + } + } + return tApp, ctx, cdpKeeper +} + +func BenchmarkCdpIteration(b *testing.B) { + benchmarks := []struct { + name string + numberCdps int + }{ + {"1000 Cdps", 1000}, + {"10000 Cdps", 10000}, + {"100000 Cdps", 100000}, + } + for _, bm := range benchmarks { + b.Run(bm.name, func(b *testing.B) { + _, ctx, cdpKeeper := createCdps(bm.numberCdps) + b.ResetTimer() + for i := 0; i < b.N; i++ { + cdpKeeper.IterateAllCdps(ctx, func(c cdp.CDP) (stop bool) { + coinsResult = c.Principal + return false + }) + } + }) + } + +} + +var errResult sdk.Error + +func BenchmarkCdpCreation(b *testing.B) { + tApp := app.NewTestApp() + ctx := tApp.NewContext(true, abci.Header{Height: 1, Time: tmtime.Now()}) + _, addrs := app.GeneratePrivKeyAddressPairs(b.N) + coins := []sdk.Coins{} + for i := 0; i < b.N; i++ { + coins = append(coins, cs(c("btc", 100000000))) + } + authGS := app.NewAuthGenState( + addrs, coins) + tApp.InitializeFromGenesisStates( + authGS, + NewPricefeedGenStateMulti(), + NewCDPGenStateMulti(), + ) + cdpKeeper := tApp.GetCDPKeeper() + b.ResetTimer() + for i := 0; i < b.N; i++ { + err := cdpKeeper.AddCdp(ctx, addrs[i], coins[i], cs(c("usdx", 100000000))) + if err != nil { + b.Error("unexpected error") + } + errResult = err + } +}