Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Effectiveness of Address Format Change and Next Action #578

Closed
4 tasks done
torao opened this issue Jul 5, 2022 · 4 comments · Fixed by #603
Closed
4 tasks done

Effectiveness of Address Format Change and Next Action #578

torao opened this issue Jul 5, 2022 · 4 comments · Fixed by #603
Assignees

Comments

@torao
Copy link
Contributor

torao commented Jul 5, 2022

Summary

This task is to sort out useful features in order to reduce the differences between lbm-sdk and cosmos-sdk.

Report on how effective the address format changes in #298 has worked/is expected to work, and complete the work if we're reverting it back to the cosmos-sdk implementation. Expected results are:

  • Report on the effects of lbm-sdk style implementations (e.g., performance measurements, design insights, considerations, etc.).
  • Decision whether to keep the lbm-sdk implementation or revert to the cosmos-sdk implementation.
  • If revert to a cosmos-sdk implementation, plan to complete that work.

Parent: #549


For Admin Use

  • Not duplicate issue
  • Appropriate labels applied
  • Appropriate contributors tagged
  • Contributor assigned/self-assigned
@ulbqb
Copy link
Member

ulbqb commented Jul 5, 2022

1. Summary

This is a post about "8 Address Format" in comment. The relevant part of "8 Address Format" has been fixed by #298. We would like to compare lbm-sdk@v0.46.0-rc2 and cosmos-sdk@v0.45.1 for the relevant part of "8 Address Format" and reflect the better correction. I measured Number of Executions and Microbenchmark as the judgment material.

2. Target Functions for Comparison

I measured the functions that seemed to have the greatest impact on execution time.

3. Number of Executions of Target Functions

Measuring method

When the following command is executed and a transaction is sent, the number of times string () is executed for one address is measured. I also measured the total number of executions of the target function when no transaction was sent (that is total number of execution per no tx block generation).

echo "y" | simd tx bank send SENDER_ADDR RECEIVER_ADDR 1stake --keyring-backend test --chain-id sim --home ~/.simapp/simapp0

Results

The result of the number of executions per address is as follows.

  • When the address is used for the first time:

    • SENDER_ADDR: 56 times
    • RECEIVER_ADDR: 11 times
  • When the address was used in the past:

    • SENDER_ADDR: 54 times
    • RECEIVER_ADDR: 9 times

The result of total number of execution per no tx block generation is 69 times

For simplicity, it is assumed that all addresses are used for the first time this time. From the above result, the total number of executions of the target function per block generation is expressed by the following formula.

total number of execution per block generation =  69 + (56 + 11) * tx_num

4. Microbenchmark of Target Functions

Execution environment

Docker on M1 macbook pro

Benchmark method

The execution time was measured when the target function was executed once, 11 times and 56 times. From Number of Executions of Target Functions results, executing the target function 11 times and 56 times is performed to take into account the effect of the cache. See the "benchmark code" chapter in the appendix for the code and tools used for benchmarking.

Results

Function lbm-sdk cosmos-sdk
AccAddress.String() x 1 3,901 ns/op 7,572 ns/op
AccAddress.String() x 11 15,581 ns/op 21,746 ns/op
AccAddress.String() x 56 63,450 ns/op 76,944 ns/op
ValAddress.String() x 1 3,959 ns/op 7,390 ns/op
ValAddress.String() x 11 16,656 ns/op 20,772 ns/op
ValAddress.String() x 56 63,954 ns/op 74,418 ns/op
ConsAddress.String() x 1 4,086 ns/op 8,323 ns/op
ConsAddress.String() x 11 15,490 ns/op 21,561 ns/op
ConsAddress.String() x 56 63,028 ns/op 76,118 ns/op

The following results are obtained by summing up the results of executing 11 times and 56 times.

Function lbm-sdk cosmos-sdk
AccAddress.String() x (11 + 56) 79,031 ns/op 98,690 ns/op
ValAddress.String() x (11 + 56) 80,610 ns/op 95,190 ns/op
ConsAddress.String() x (11 + 56) 78,518 ns/op 97,679 ns/op

5. Discussion

Regarding the target function, the difference narrowed relatively if the number of executions was large. Also, since the target function is executed at least 69 times, there seems to be no big difference in execution time between lbm-sdk@v0.46.0-rc2 and cosmos-sdk@v0.45.1.

The total number of executions of the target function per block generation is expressed by the following formula.

total number of execution per block generation =  69 + (56 + 11) * tx_num

Ignore 69 times (total number of execution per no tx block generation), from the result of AccAddress.String() x (11 + 56), the execution time ratio of lbm-sdk and cosmos-sdk is about 4:5. there seems to be no big difference in execution time between lbm-sdk and cosmos-sdk.

6. Appendix

Benchmark code

go test -bench . -benchmem
lbm_vs_cosmos_test.go
package main

import (
	"math/rand"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	lbm_ed25519 "github.com/line/lbm-sdk/crypto/keys/ed25519"
	lbm_types "github.com/line/lbm-sdk/types"

	csms_ed25519 "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
	csms_types "github.com/cosmos/cosmos-sdk/types"
	csms_bech32 "github.com/cosmos/cosmos-sdk/types/bech32"
)

func BenchmarkLbmAccAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := lbm_types.BytesToAccAddress(pk.Address())
		str := string(acc)

		b.StartTimer()
		str2 := acc.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkLbmAccAddressString11Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := lbm_types.BytesToAccAddress(pk.Address())
		str := string(acc)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := acc.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkLbmAccAddressString56Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := lbm_types.BytesToAccAddress(pk.Address())
		str := string(acc)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := acc.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkLbmValAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := lbm_types.BytesToValAddress(pk.Address())
		str := string(val)

		b.StartTimer()
		str2 := val.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkLbmValAddressString11Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := lbm_types.BytesToValAddress(pk.Address())
		str := string(val)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := val.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkLbmValAddressString56Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := lbm_types.BytesToValAddress(pk.Address())
		str := string(val)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := val.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkLbmConsAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := lbm_types.BytesToConsAddress(pk.Address())
		str := string(cons)

		b.StartTimer()
		str2 := cons.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkLbmConsAddressString11Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := lbm_types.BytesToConsAddress(pk.Address())
		str := string(cons)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := cons.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkLbmConsAddressString56Times(b *testing.B) {
	pkBz := make([]byte, lbm_ed25519.PubKeySize)
	pk := &lbm_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := lbm_types.BytesToConsAddress(pk.Address())
		str := string(cons)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := cons.String()
			require.Equal(b, str, str2)
		}
	}
}

// ---------------------------------------------------------------------------------

func BenchmarkCsmsAccAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := csms_types.AccAddress(pk.Address())
		bech32PrefixAccAddr := csms_types.GetConfig().GetBech32AccountAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixAccAddr, acc.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		str2 := acc.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkCsmsAccAddressString11Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := csms_types.AccAddress(pk.Address())
		bech32PrefixAccAddr := csms_types.GetConfig().GetBech32AccountAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixAccAddr, acc.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := acc.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkCsmsAccAddressString56Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		acc := csms_types.AccAddress(pk.Address())
		bech32PrefixAccAddr := csms_types.GetConfig().GetBech32AccountAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixAccAddr, acc.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := acc.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkCsmsValAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := csms_types.ValAddress(pk.Address())
		bech32PrefixValAddr := csms_types.GetConfig().GetBech32ValidatorAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixValAddr, val.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		str2 := val.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkCsmsValAddressString11Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := csms_types.ValAddress(pk.Address())
		bech32PrefixValAddr := csms_types.GetConfig().GetBech32ValidatorAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixValAddr, val.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := val.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkCsmsValAddressString56Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		val := csms_types.ValAddress(pk.Address())
		bech32PrefixValAddr := csms_types.GetConfig().GetBech32ValidatorAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixValAddr, val.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := val.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkCsmsConsAddressStringOneTime(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := csms_types.ConsAddress(pk.Address())
		bech32PrefixConsAddr := csms_types.GetConfig().GetBech32ConsensusAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixConsAddr, cons.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		str2 := cons.String()
		require.Equal(b, str, str2)
	}
}

func BenchmarkCsmsConsAddressString11Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := csms_types.ConsAddress(pk.Address())
		bech32PrefixConsAddr := csms_types.GetConfig().GetBech32ConsensusAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixConsAddr, cons.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 11; i++ {
			str2 := cons.String()
			require.Equal(b, str, str2)
		}
	}
}

func BenchmarkCsmsConsAddressString56Times(b *testing.B) {
	pkBz := make([]byte, csms_ed25519.PubKeySize)
	pk := &csms_ed25519.PubKey{Key: pkBz}
	rng := rand.New(rand.NewSource(time.Now().Unix()))

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.StopTimer()
		rng.Read(pk.Key)

		cons := csms_types.ConsAddress(pk.Address())
		bech32PrefixConsAddr := csms_types.GetConfig().GetBech32ConsensusAddrPrefix()
		str, err := csms_bech32.ConvertAndEncode(bech32PrefixConsAddr, cons.Bytes())
		require.NoError(b, err)

		b.StartTimer()
		for i := 0; i < 56; i++ {
			str2 := cons.String()
			require.Equal(b, str, str2)
		}
	}
}
go.mod
module lbm-vs-cosmos

go 1.15

replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1

require (
	github.com/cosmos/cosmos-sdk v0.45.1
	github.com/line/lbm-sdk v0.46.0-rc2
	github.com/stretchr/testify v1.7.1
)

@tnasu
Copy link
Member

tnasu commented Jul 6, 2022

Regarding the target function, the difference narrowed relatively if the number of executions was large. Also, since the target function is executed at least 69 times, there seems to be no big difference in execution time between lbm-sdk@v0.46.0-rc2 and cosmos-sdk@v0.45.1.

I agree with you. In my opinion, let's rollbacks these codes.

@torao How about you?

@zemyblue
Copy link
Member

zemyblue commented Jul 6, 2022

Regarding the target function, the difference narrowed relatively if the number of executions was large. Also, since the target function is executed at least 69 times, there seems to be no big difference in execution time between lbm-sdk@v0.46.0-rc2 and cosmos-sdk@v0.45.1.

I agree with you. In my opinion, let's rollbacks these codes.

@torao How about you?

I also agree @tnasu 's opinion.

@ulbqb
Copy link
Member

ulbqb commented Jul 7, 2022

Fixed the result.

@tnasu @zemyblue
I'm sorry, it seems that the latest results weren't reflected when you were commenting. But the result remains the same. there seems to be no big difference in execution time between lbm-sdk and cosmos-sdk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants