Skip to content

Commit

Permalink
Chore: Minor performance improvements and extra benchmark tests (#136)
Browse files Browse the repository at this point in the history
* Minor optimization infer res

* Add assert equal benchmarks
  • Loading branch information
rodrigo-pino authored Oct 24, 2023
1 parent 1feb71e commit 86c612e
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 13 deletions.
17 changes: 16 additions & 1 deletion pkg/vm/memory/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (segment *Segment) Read(offset uint64) (MemoryValue, error) {

func (segment *Segment) Peek(offset uint64) MemoryValue {
if offset >= segment.RealLen() {
segment.IncreaseSegmentSize(offset + 1)
return UnknownValue
}
return segment.Data[offset]
}
Expand Down Expand Up @@ -267,6 +267,21 @@ func (memory *Memory) PeekFromAddress(address *MemoryAddress) (MemoryValue, erro
return memory.Peek(address.SegmentIndex, address.Offset)
}

// Given a segment index and offset returns true if the value at that address
// is known
func (memory *Memory) KnownValue(segment uint64, offset uint64) bool {
if segment >= uint64(len(memory.Segments)) ||
offset >= uint64(len(memory.Segments[segment].Data)) {
return false
}
return memory.Segments[segment].Data[offset].Known()
}

// Given an address returns true if it contains a known value
func (memory *Memory) KnownValueAtAddress(address *MemoryAddress) bool {
return memory.KnownValue(address.SegmentIndex, address.Offset)
}

// It returns all segment offsets and max memory used
func (memory *Memory) RelocationOffsets() ([]uint64, uint64) {
// Prover expects maxMemoryUsed to start at one
Expand Down
19 changes: 7 additions & 12 deletions pkg/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (vm *VirtualMachine) RunInstruction(instruction *a.Instruction) error {

res, err := vm.inferOperand(instruction, &dstAddr, &op0Addr, &op1Addr)
if err != nil {
return fmt.Errorf("res infer: %w", err)
return fmt.Errorf("infer res: %w", err)
}
if !res.Known() {
res, err = vm.computeRes(instruction, &op0Addr, &op1Addr)
Expand Down Expand Up @@ -261,11 +261,11 @@ func (vm *VirtualMachine) getOp1Addr(instruction *a.Instruction, op0Addr *mem.Me
op1Address = vm.Context.AddressAp()
}

addr, isOverflow := safemath.SafeOffset(op1Address.Offset, instruction.OffOp1)
newOffset, isOverflow := safemath.SafeOffset(op1Address.Offset, instruction.OffOp1)
if isOverflow {
return mem.UnknownAddress, fmt.Errorf("offset overflow: %d + %d", op1Address.Offset, instruction.OffOp1)
}
op1Address.Offset = addr
op1Address.Offset = newOffset
return op1Address, nil
}

Expand All @@ -277,18 +277,13 @@ func (vm *VirtualMachine) inferOperand(
instruction *a.Instruction, dstAddr *mem.MemoryAddress, op0Addr *mem.MemoryAddress, op1Addr *mem.MemoryAddress,
) (mem.MemoryValue, error) {
if instruction.Opcode != a.OpCodeAssertEq ||
(instruction.Res == a.Unconstrained) {
instruction.Res == a.Unconstrained ||
!vm.Memory.KnownValueAtAddress(dstAddr) {
return mem.MemoryValue{}, nil
}

dstValue, err := vm.Memory.PeekFromAddress(dstAddr)
if err != nil {
return mem.MemoryValue{}, fmt.Errorf("cannot read dst: %w", err)
}

if !dstValue.Known() {
return mem.MemoryValue{}, nil // let computeRes try to handle it
}
// we known dst value is known due to previous check
dstValue, _ := vm.Memory.PeekFromAddress(dstAddr)

op0Value, err := vm.Memory.PeekFromAddress(op0Addr)
if err != nil {
Expand Down
124 changes: 124 additions & 0 deletions pkg/vm/vm_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package vm

import (
"testing"
)

func BenchmarkAssertEqual(b *testing.B) {
b.Run("assign left to rigth", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap] = [ap - 1], ap++;
`)
writeToDataSegment(vm, 1, 3)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset--
}
})
b.Run("assign right to left", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap - 1] = [ap], ap++;
`)
writeToDataSegment(vm, 1, 3)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset--
}
})
b.Run("addition", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap] = [ap - 1] + [ap - 2], ap++;
`)
writeToDataSegment(vm, 0, 1)
writeToDataSegment(vm, 1, 1)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset--
}
})
b.Run("substraction", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap] = [ap - 1] + [ap - 2];
[ap + 2] = [ap - 1];
ap += 2;
`)
writeToDataSegment(vm, 0, 7)
writeToDataSegment(vm, 2, 10)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset %= 4
}
})
b.Run("multiplication", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap] = [ap - 1] * [ap - 2] , ap++;
`)
writeToDataSegment(vm, 0, 2)
writeToDataSegment(vm, 1, 3)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset--
}
})
b.Run("divition", func(b *testing.B) {
vm := defaultVirtualMachineWithCode(`
[ap] = [ap - 1] * [ap - 2];
[ap + 2] = [ap - 1];
ap += 2;
`)
writeToDataSegment(vm, 0, 4)
writeToDataSegment(vm, 2, 20)
vm.Context.Ap = 2
vm.Context.Fp = 2

noHr := noHintRunner{}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := vm.RunStep(&noHr); err != nil {
b.Error(err)
break
}
vm.Context.Pc.Offset %= 4
}
})
}

0 comments on commit 86c612e

Please sign in to comment.