core/vm: fix benchmarks

Marius van der Wijden 2 months ago committed by Martin HS
parent 34dff6a4cf
commit 84591bf289
  1. 58
      core/vm/validate_test.go

@ -258,6 +258,8 @@ func TestValidateCode(t *testing.T) {
} }
} }
// BenchmarkRJUMPI tries to benchmark the RJUMPI opcode validation
// For this we do a bunch of RJUMPIs that jump backwards (in a potential infinite loop).
func BenchmarkRJUMPI(b *testing.B) { func BenchmarkRJUMPI(b *testing.B) {
snippet := []byte{ snippet := []byte{
byte(PUSH0), byte(PUSH0),
@ -275,13 +277,15 @@ func BenchmarkRJUMPI(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, true) _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
// BenchmarkRJUMPV tries to benchmark the validation of the RJUMPV opcode
// for this we set up as many RJUMPV opcodes with a full jumptable (containing 0s) as possible.
func BenchmarkRJUMPV(b *testing.B) { func BenchmarkRJUMPV(b *testing.B) {
snippet := []byte{ snippet := []byte{
byte(PUSH0), byte(PUSH0),
@ -305,13 +309,18 @@ func BenchmarkRJUMPV(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, true) _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
// BenchmarkEOFValidation tries to benchmark the code validation for the CALLF/RETF operation.
// For this we set up code that calls into 1024 code sections which can either
// - just contain a RETF opcode
// - or code to again call into 1024 code sections.
// We can't have all code sections calling each other, otherwise we would exceed 48KB.
func BenchmarkEOFValidation(b *testing.B) { func BenchmarkEOFValidation(b *testing.B) {
var container Container var container Container
var code []byte var code []byte
@ -320,22 +329,21 @@ func BenchmarkEOFValidation(b *testing.B) {
code = append(code, byte(CALLF)) code = append(code, byte(CALLF))
code = binary.BigEndian.AppendUint16(code, uint16(i%(maxSections-1))+1) code = binary.BigEndian.AppendUint16(code, uint16(i%(maxSections-1))+1)
} }
code = append(code, byte(STOP))
// First container // First container
container.codeSections = append(container.codeSections, code) container.codeSections = append(container.codeSections, append(code, byte(STOP)))
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 0}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 0})
inner := []byte{ inner := []byte{
byte(STOP), byte(RETF),
} }
for i := 0; i < 1023; i++ { for i := 0; i < 1023; i++ {
container.codeSections = append(container.codeSections, inner) container.codeSections = append(container.codeSections, inner)
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 0}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0, maxStackHeight: 0})
} }
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
container.codeSections[i+1] = code container.codeSections[i+1] = append(code, byte(RETF))
} }
bin := container.MarshalBinary() bin := container.MarshalBinary()
@ -349,12 +357,16 @@ func BenchmarkEOFValidation(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, true); err != nil { if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
// BenchmarkEOFValidation tries to benchmark the code validation for the CALLF/RETF operation.
// For this we set up code that calls into 1024 code sections which
// - contain calls to some other code sections.
// We can't have all code sections calling each other, otherwise we would exceed 48KB.
func BenchmarkEOFValidation2(b *testing.B) { func BenchmarkEOFValidation2(b *testing.B) {
var container Container var container Container
var code []byte var code []byte
@ -380,12 +392,13 @@ func BenchmarkEOFValidation2(b *testing.B) {
byte(CALLF), 0x03, 0xF6, byte(CALLF), 0x03, 0xF6,
byte(CALLF), 0x03, 0xF7, byte(CALLF), 0x03, 0xF7,
byte(CALLF), 0x03, 0xF8, byte(CALLF), 0x03, 0xF8,
byte(JUMPF), 0x00, 0x00, byte(CALLF), 0x03, 0xF,
byte(RETF),
} }
for i := 0; i < 1023; i++ { for i := 0; i < 1023; i++ {
container.codeSections = append(container.codeSections, inner) container.codeSections = append(container.codeSections, inner)
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 0}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0, maxStackHeight: 0})
} }
bin := container.MarshalBinary() bin := container.MarshalBinary()
@ -399,12 +412,17 @@ func BenchmarkEOFValidation2(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, true); err != nil { if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
} }
// BenchmarkEOFValidation3 tries to benchmark the code validation for the CALLF/RETF and RJUMPI/V operations.
// For this we set up code that calls into 1024 code sections which either
// - contain an RJUMP opcode
// - contain calls to other code sections
// We can't have all code sections calling each other, otherwise we would exceed 48KB.
func BenchmarkEOFValidation3(b *testing.B) { func BenchmarkEOFValidation3(b *testing.B) {
var container Container var container Container
var code []byte var code []byte
@ -418,23 +436,25 @@ func BenchmarkEOFValidation3(b *testing.B) {
snippet = append(snippet, []byte{0x00, 0x00}...) snippet = append(snippet, []byte{0x00, 0x00}...)
} }
code = append(code, snippet...) code = append(code, snippet...)
// First container, calls into all other containers
maxSections := 1024 maxSections := 1024
for i := 0; i < maxSections; i++ { for i := 0; i < maxSections; i++ {
code = append(code, byte(CALLF)) code = append(code, byte(CALLF))
code = binary.BigEndian.AppendUint16(code, uint16(i%(maxSections-1))+1) code = binary.BigEndian.AppendUint16(code, uint16(i%(maxSections-1))+1)
} }
code = append(code, byte(STOP)) code = append(code, byte(STOP))
// First container
container.codeSections = append(container.codeSections, code) container.codeSections = append(container.codeSections, code)
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 1}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 1})
// Other containers
for i := 0; i < 1023; i++ { for i := 0; i < 1023; i++ {
container.codeSections = append(container.codeSections, []byte{byte(RJUMP), 0x00, 0x00, byte(JUMPF), 0x00, 0x00}) container.codeSections = append(container.codeSections, []byte{byte(RJUMP), 0x00, 0x00, byte(RETF)})
container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 0}) container.types = append(container.types, &functionMetadata{inputs: 0, outputs: 0, maxStackHeight: 0})
} }
for i := 0; i < 65; i++ { // Other containers
container.codeSections[i+1] = append(snippet, byte(STOP)) for i := 0; i < 68; i++ {
container.types[i+1] = &functionMetadata{inputs: 0, outputs: 0x80, maxStackHeight: 1} container.codeSections[i+1] = append(snippet, byte(RETF))
container.types[i+1] = &functionMetadata{inputs: 0, outputs: 0, maxStackHeight: 1}
} }
bin := container.MarshalBinary() bin := container.MarshalBinary()
if len(bin) > 48*1024 { if len(bin) > 48*1024 {
@ -448,7 +468,7 @@ func BenchmarkEOFValidation3(b *testing.B) {
if err := container2.UnmarshalBinary(bin, true); err != nil { if err := container2.UnmarshalBinary(bin, true); err != nil {
b.Fatal(err) b.Fatal(err)
} }
if err := container2.ValidateCode(&pragueEOFInstructionSet, true); err != nil { if err := container2.ValidateCode(&pragueEOFInstructionSet, false); err != nil {
b.Fatal(err) b.Fatal(err)
} }
} }
@ -474,7 +494,7 @@ func BenchmarkRJUMPI_2(b *testing.B) {
} }
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
_, err := validateCode(code, 0, container, &pragueEOFInstructionSet, true) _, err := validateCode(code, 0, container, &pragueEOFInstructionSet, false)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }

Loading…
Cancel
Save