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

AVM: Clearer cost benchmarks, and a nice optimization of b== and b< #5010

Merged
merged 3 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -1822,6 +1822,15 @@ func opBytesSqrt(cx *EvalContext) error {
return nil
}

func nonzero(b []byte) []byte {
for i := range b {
if b[i] != 0 {
return b[i:]
}
}
return nil
}

func opBytesLt(cx *EvalContext) error {
last := len(cx.stack) - 1
prev := last - 1
Expand All @@ -1830,9 +1839,11 @@ func opBytesLt(cx *EvalContext) error {
return errors.New("math attempted on large byte-array")
}

rhs := new(big.Int).SetBytes(cx.stack[last].Bytes)
lhs := new(big.Int).SetBytes(cx.stack[prev].Bytes)
cx.stack[prev] = boolToSV(lhs.Cmp(rhs) < 0)
rhs := nonzero(cx.stack[last].Bytes)
lhs := nonzero(cx.stack[prev].Bytes)

cx.stack[prev] = boolToSV(len(lhs) < len(rhs) || bytes.Compare(lhs, rhs) < 0)

cx.stack = cx.stack[:last]
return nil
}
Expand Down Expand Up @@ -1866,9 +1877,10 @@ func opBytesEq(cx *EvalContext) error {
return errors.New("math attempted on large byte-array")
}

rhs := new(big.Int).SetBytes(cx.stack[last].Bytes)
lhs := new(big.Int).SetBytes(cx.stack[prev].Bytes)
cx.stack[prev] = boolToSV(lhs.Cmp(rhs) == 0)
rhs := nonzero(cx.stack[last].Bytes)
lhs := nonzero(cx.stack[prev].Bytes)

cx.stack[prev] = boolToSV(bytes.Equal(lhs, rhs))
cx.stack = cx.stack[:last]
return nil
}
Expand Down
23 changes: 16 additions & 7 deletions data/transactions/logic/evalCrypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,27 @@ func BenchmarkVerify(b *testing.B) {
benches := [][]string{
{"pop", "", "int 1234576; int 6712; pop; pop", "int 1"},
{"add", "", "int 1234576; int 6712; +; pop", "int 1"},
/*
{"ed25519verify_bare", "", `byte 0x
byte 0x
addr
ed25519verify_bare
assert`, "int 1"},*/
{"ecdsa_verify", "", `byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
{"ed25519verify_bare", "", `
byte 0x62fdfc072182654f163f5f0f9a621d729566c74d0aa413bf009c9800418c19cd
byte 0xaab40a8b4f1f386504af2473804abbc03bbd94506e8e0c8db881fc2b2c3aee65b867b25caa47fa25ae2105bf1731398df336213707f2d25f9b1d31b3dc133307;
addr C7ZCK6N2AJQMVEP4FRTK2UW45UFR6DKPRJHJVWB5O4VQOZMFPK2KCMR7M4
ed25519verify_bare; assert
`, "int 1"},
{"ecdsa_verify k1", "", `
byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
byte 0x5eb27782eb1a5df8de9a5d51613ad5ca730840ddf4af919c6feb15cde14f9978
byte 0x0cb3c0d636ed991ee030d09c295de3121eb166cb9e1552cf0ef0fb2358f35f0f
byte 0x79de0699673571df1de8486718d06a3e7838f6831ec4ef3fb963788fbfb773b7
byte 0xd76446a3393af3e2eefada16df80cc6a881a56f4cf41fa2ab4769c5708ce878d
ecdsa_verify Secp256k1
assert`, "int 1"},
{"ecdsa_verify r1", "", `
byte 0x71a5910445820f57989c027bdf9391c80097874d249e0f38bf90834fdec2877f
byte 0xc010fc83ea196d6f5ce8a44637060bdcfb5bf1199cfc5bb893684d450c4f160c
byte 0x8e391a7b9cd75a99e8ebfe703036caebd9e91ae8339bd7e2abfb0f273eb8e972
byte 0x13e49a19378bbfa8d55ac81a35b87d7bae456c79fcf04a78803d8eb45b253fab
byte 0xa2d237cd897ca70787abf04d2155c6dc2fbe26fd642e0472cd75c13dc919ef1a
ecdsa_verify Secp256r1
assert`, "int 1"},
{"vrf_verify", "", `byte 0x72
byte 0xae5b66bdf04b4c010bfe32b2fc126ead2107b697634f6f7337b9bff8785ee111200095ece87dde4dbe87343f6df3b107d91798c8a7eb1245d3bb9c5aafb093358c13e6ae1111a55717e895fd15f99f07
Expand Down
164 changes: 110 additions & 54 deletions data/transactions/logic/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3728,27 +3728,37 @@ main:
}

func BenchmarkByteLogic(b *testing.B) {
e64 := "byte 0x8090a0b0c0d0e0f0;"
o64 := "byte 0x1020304050607080;"
hex128e := "90a0b0c0d0e0f0001020304050607080"
hex128o := "102030405060708090a0b0c0d0e0f000"
e128 := "byte 0x" + strings.Repeat(hex128e, 1) + ";"
o128 := "byte 0x" + strings.Repeat(hex128o, 1) + ";"
e256 := "byte 0x" + strings.Repeat(hex128e, 2) + ";"
o256 := "byte 0x" + strings.Repeat(hex128o, 2) + ";"
e512 := "byte 0x" + strings.Repeat(hex128e, 4) + ";"
o512 := "byte 0x" + strings.Repeat(hex128o, 4) + ";"

benches := [][]string{
{"b&", "", "byte 0x012345678901feab; byte 0x01ffffffffffffff; b&; pop", "int 1"},
{"b|", "", "byte 0x0ffff1234576abef; byte 0x1202120212021202; b|; pop", "int 1"},
{"b^", "", "byte 0x0ffff1234576abef; byte 0x1202120212021202; b^; pop", "int 1"},
{"b~", "byte 0x0123457673624736", "b~", "pop; int 1"},

{"b&big",
"byte 0x0123457601234576012345760123457601234576012345760123457601234576",
"byte 0x01ffffffffffffff01ffffffffffffff01234576012345760123457601234576; b&",
"pop; int 1"},
{"b|big",
"byte 0x0123457601234576012345760123457601234576012345760123457601234576",
"byte 0xffffff01ffffffffffffff01234576012345760123457601234576; b|",
"pop; int 1"},
{"b^big", "", // u256^u256
`byte 0x123457601234576012345760123457601234576012345760123457601234576a
byte 0xf123457601234576012345760123457601234576012345760123457601234576; b^; pop`,
"int 1"},
{"b~big", "byte 0xa123457601234576012345760123457601234576012345760123457601234576",
"b~",
"pop; int 1"},
{"b& 8", "", e64 + o64 + "b&; pop", "int 1"},
{"b| 8", "", e64 + o64 + "b|; pop", "int 1"},
{"b^ 8", "", e64 + o64 + "b^; pop", "int 1"},
{"b~ 8", e64, "b~", "pop; int 1"},

{"b& 16", "", e128 + o128 + "b&; pop", "int 1"},
{"b| 16", "", e128 + o128 + "b|; pop", "int 1"},
{"b^ 16", "", e128 + o128 + "b^; pop", "int 1"},
{"b~ 16", e128, "b~", "pop; int 1"},

{"b& 32", "", e256 + o256 + "b&; pop", "int 1"},
{"b| 32", "", e256 + o256 + "b|; pop", "int 1"},
{"b^ 32", "", e256 + o256 + "b^; pop", "int 1"},
{"b~ 32", e256, "b~", "pop; int 1"},

{"b& 64", "", e512 + o512 + "b&; pop", "int 1"},
{"b| 64", "", e512 + o512 + "b|; pop", "int 1"},
{"b^ 64", "", e512 + o512 + "b^; pop", "int 1"},
{"b~ 64", e512, "b~", "pop; int 1"},
}
for _, bench := range benches {
b.Run(bench[0], func(b *testing.B) {
Expand All @@ -3759,44 +3769,79 @@ func BenchmarkByteLogic(b *testing.B) {
}

func BenchmarkByteMath(b *testing.B) {
u64 := "byte 0x8090a0b0c0d0e0f0;"
hex128 := "102030405060708090a0b0c0d0e0f000"
u128 := "byte 0x" + strings.Repeat(hex128, 1) + ";"
u256 := "byte 0x" + strings.Repeat(hex128, 2) + ";"
u512 := "byte 0x" + strings.Repeat(hex128, 4) + ";"

benches := [][]string{
{"bpop", "", "byte 0x01ffffffffffffff; pop", "int 1"},

{"b+", "byte 0x01234576", "byte 0x01ffffffffffffff; b+", "pop; int 1"},
{"b-", "byte 0x0ffff1234576", "byte 0x1202; b-", "pop; int 1"},
{"b*", "", "byte 0x01234576; byte 0x0223627389; b*; pop", "int 1"},
{"b/", "", "byte 0x0123457673624736; byte 0x0223627389; b/; pop", "int 1"},
{"b%", "", "byte 0x0123457673624736; byte 0x0223627389; b/; pop", "int 1"},
{"bsqrt", "", "byte 0x0123457673624736; bsqrt; pop", "int 1"},

{"b+big", // u256 + u256
"byte 0x0123457601234576012345760123457601234576012345760123457601234576",
"byte 0x01ffffffffffffff01ffffffffffffff01234576012345760123457601234576; b+",
"pop; int 1"},
{"b-big", // second is a bit small, so we can subtract it over and over
"byte 0x0123457601234576012345760123457601234576012345760123457601234576",
"byte 0xffffff01ffffffffffffff01234576012345760123457601234576; b-",
"pop; int 1"},
{"b*big", "", // u256*u256
`byte 0xa123457601234576012345760123457601234576012345760123457601234576
byte 0xf123457601234576012345760123457601234576012345760123457601234576; b*; pop`,
"int 1"},
{"b/big", "", // u256 / u128 (half sized divisor seems pessimal)
`byte 0xa123457601234576012345760123457601234576012345760123457601234576
byte 0x34576012345760123457601234576312; b/; pop`,
"int 1"},
{"b%big", "", // u256 / u128 (half sized divisor seems pessimal)
`byte 0xa123457601234576012345760123457601234576012345760123457601234576
byte 0x34576012345760123457601234576312; b/; pop`,
"int 1"},
{"bsqrt-big", "",
`byte 0xa123457601234576012345760123457601234576012345760123457601234576
bsqrt; pop`,
"int 1"},
{"bytec", u128 + "pop"},

{"b+ 128", u128 + u128 + "b+; pop"},
{"b- 128", u128 + u128 + "b-; pop"},
{"b* 128", u128 + u128 + "b*; pop"},
// half sized divisor seems pessimal for / and %
{"b/ 128", u128 + u64 + "b/; pop"},
{"b% 128", u128 + u64 + "b%; pop"},
{"bsqrt 128", u128 + "bsqrt; pop"},

{"b+ 256", u256 + u256 + "b+; pop"},
{"b- 256", u256 + u256 + "b-; pop"},
{"b* 256", u256 + u256 + "b*; pop"},
{"b/ 256", u256 + u128 + "b/; pop"},
{"b% 256", u256 + u128 + "b%; pop"},
{"bsqrt 256", u256 + "bsqrt; pop"},

{"b+ 512", u512 + u512 + "b+; pop"},
{"b- 512", u512 + u512 + "b-; pop"},
{"b* 512", u512 + u512 + "b*; pop"},
{"b/ 512", u512 + u256 + "b/; pop"},
{"b% 512", u512 + u256 + "b%; pop"},
{"bsqrt 512", u512 + "bsqrt; pop"},

{"bytec recheck", u128 + "pop"},
}
for _, bench := range benches {
b.Run(bench[0], func(b *testing.B) {
benchmarkOperation(b, bench[1], bench[2], bench[3])
b.ReportAllocs()
benchmarkOperation(b, "", bench[1], "int 1")
})
}
}

func BenchmarkByteCompare(b *testing.B) {
u64 := "byte 0x8090a0b0c0d0e0f0;"
hex128 := "102030405060708090a0b0c0d0e0f000"
u128 := "byte 0x" + strings.Repeat(hex128, 1) + ";"
u256 := "byte 0x" + strings.Repeat(hex128, 2) + ";"
u512 := "byte 0x" + strings.Repeat(hex128, 4) + ";"
//u4k := "byte 0x" + strings.Repeat(hex128, 256) + ";"

benches := [][]string{
{"b== 64", u64 + u64 + "b==; pop"},
{"b< 64", u64 + u64 + "b<; pop"},
{"b<= 64", u64 + u64 + "b<=; pop"},
{"b== 128", u128 + u128 + "b==; pop"},
{"b< 128", u128 + u128 + "b<; pop"},
{"b<= 128", u128 + u128 + "b<=; pop"},
{"b== 256", u256 + u256 + "b==; pop"},
{"b< 256", u256 + u256 + "b<; pop"},
{"b<= 256", u256 + u256 + "b<=; pop"},
{"b== 512", u512 + u512 + "b==; pop"},
{"b< 512", u512 + u512 + "b<; pop"},
{"b<= 512", u512 + u512 + "b<=; pop"},
// These can only be run with the maxByteMathSize check removed. They
// show that we can remove that check in a later AVM version, as there
// is no appreciable cost to even a 4k compare.
// {"b== 4k", u4k + u4k + "b==; pop"},
// {"b< 4k", u4k + u4k + "b<; pop"},
// {"b<= 4k", u4k + u4k + "b<=; pop"},
}
for _, bench := range benches {
b.Run(bench[0], func(b *testing.B) {
b.ReportAllocs()
benchmarkOperation(b, "", bench[1], "int 1")
})
}
}
Expand Down Expand Up @@ -4871,9 +4916,20 @@ func TestBytesCompare(t *testing.T) {
testPanics(t, "byte 0x10; int 65; bzero; b<=", 4)
testAccepts(t, "byte 0x10; int 64; bzero; b>", 4)
testPanics(t, "byte 0x10; int 65; bzero; b>", 4)
testAccepts(t, "byte 0x1010; byte 0x10; b<; !", 4)

// All zero input are interesting, because they lead to bytes.Compare being
// called with nils. Show that is correct.
testAccepts(t, "byte 0x10; byte 0x00; b<; !", 4)
testAccepts(t, "byte 0x10; byte 0x0000; b<; !", 4)
testAccepts(t, "byte 0x00; byte 0x10; b<", 4)
testAccepts(t, "byte 0x0000; byte 0x10; b<", 4)
testAccepts(t, "byte 0x0000; byte 0x00; b<; !", 4)
testAccepts(t, "byte 0x; byte 0x00; b==", 4)

testAccepts(t, "byte 0x11; byte 0x10; b>", 4)
testAccepts(t, "byte 0x11; byte 0x0010; b>", 4)
testAccepts(t, "byte 0x1010; byte 0x11; b>", 4)

testAccepts(t, "byte 0x11; byte 0x10; b>=", 4)
testAccepts(t, "byte 0x11; byte 0x0011; b>=", 4)
Expand Down