Skip to content

Commit

Permalink
perf: for loop and if (#2140)
Browse files Browse the repository at this point in the history
solves [this](#2138)

Benchmarks
```
Master
BenchmarkIfStatement-10    	     238	   4967960 ns/op
BenchmarkForLoop-10    	          649	   1771728 ns/op

Current branch
BenchmarkIfStatement-10    	     366	   3316189 ns/op
BenchmarkForLoop-10    	         1143	    945930 ns/op
```

By avoiding the runtime type conversion, we can see that we almost
doubled the performance of these statements.

---------

Co-authored-by: jaekwon <jae@tendermint.com>
Co-authored-by: Jae Kwon <53785+jaekwon@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 19, 2024
1 parent 0ba53ac commit 71a298b
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 15 deletions.
32 changes: 32 additions & 0 deletions gnovm/pkg/gnolang/gno_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,38 @@ func main() {
m.RunMain()
}

func BenchmarkPreprocessForLoop(b *testing.B) {
m := NewMachine("test", nil)
c := `package test
func main() {
for i:=0; i<10000; i++ {}
}`
n := MustParseFile("main.go", c)
m.RunFiles(n)

for i := 0; i < b.N; i++ {
m.RunMain()
}
}

func BenchmarkIfStatement(b *testing.B) {
m := NewMachine("test", nil)
c := `package test
func main() {
for i:=0; i<10000; i++ {
if i > 10 {
}
}
}`
n := MustParseFile("main.go", c)
m.RunFiles(n)

for i := 0; i < b.N; i++ {
m.RunMain()
}
}

func TestDoOpEvalBaseConversion(t *testing.T) {
m := NewMachine("test", nil)

Expand Down
4 changes: 4 additions & 0 deletions gnovm/pkg/gnolang/op_inc_dec.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func (m *Machine) doOpInc() {
panic("expected lv.V to be nil for primitive type for OpInc")
}
}

// here we can't just switch on the value type
// because it could be a type alias
// type num int
switch baseOf(lv.T) {
case IntType:
lv.SetInt(lv.GetInt() + 1)
Expand Down
48 changes: 35 additions & 13 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1253,7 +1253,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
case StringKind, ArrayKind, SliceKind:
// Replace const index with int *ConstExpr,
// or if not const, assert integer type..
checkOrConvertIntegerType(store, last, n.Index)
checkOrConvertIntegerKind(store, last, n.Index)
case MapKind:
mt := baseOf(gnoTypeOf(store, dt)).(*MapType)
checkOrConvertType(store, last, &n.Index, mt.Key, false)
Expand All @@ -1267,9 +1267,9 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
case *SliceExpr:
// Replace const L/H/M with int *ConstExpr,
// or if not const, assert integer type..
checkOrConvertIntegerType(store, last, n.Low)
checkOrConvertIntegerType(store, last, n.High)
checkOrConvertIntegerType(store, last, n.Max)
checkOrConvertIntegerKind(store, last, n.Low)
checkOrConvertIntegerKind(store, last, n.High)
checkOrConvertIntegerKind(store, last, n.Max)

// TRANS_LEAVE -----------------------
case *TypeAssertExpr:
Expand Down Expand Up @@ -1728,12 +1728,12 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
// TRANS_LEAVE -----------------------
case *ForStmt:
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
checkOrConvertBoolKind(store, last, n.Cond)

// TRANS_LEAVE -----------------------
case *IfStmt:
// Cond consts become bool *ConstExprs.
checkOrConvertType(store, last, &n.Cond, BoolType, false)
checkOrConvertBoolKind(store, last, n.Cond)

// TRANS_LEAVE -----------------------
case *RangeStmt:
Expand Down Expand Up @@ -2474,7 +2474,7 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
// autoNative is usually false, but set to true
// for native function calls, where gno values are
// automatically converted to native go types.
// NOTE: also see checkOrConvertIntegerType()
// NOTE: also see checkOrConvertIntegerKind()
func convertType(store Store, last BlockNode, x *Expr, t Type) {
if debug {
debug.Printf("convertType, *x: %v:, t:%v \n", *x, t)
Expand Down Expand Up @@ -2783,26 +2783,48 @@ func findUndefined2(store Store, last BlockNode, x Expr, t Type) (un Name) {
return
}

// like checkOrConvertType() but for any integer type.
func checkOrConvertIntegerType(store Store, last BlockNode, x Expr) {
// like checkOrConvertType() but for any typed bool kind.
func checkOrConvertBoolKind(store Store, last BlockNode, x Expr) {
if cx, ok := x.(*ConstExpr); ok {
convertConst(store, last, cx, BoolType)
} else if x != nil {
xt := evalStaticTypeOf(store, last, x)
checkBoolKind(xt)
}
}

// assert that xt is a typed bool kind.
func checkBoolKind(xt Type) {
switch xt.Kind() {
case BoolKind:
return // ok
default:
panic(fmt.Sprintf(
"expected typed bool kind, but got %v",
xt.Kind()))
}
}

// like checkOrConvertType() but for any typed integer kind.
func checkOrConvertIntegerKind(store Store, last BlockNode, x Expr) {
if cx, ok := x.(*ConstExpr); ok {
convertConst(store, last, cx, IntType)
} else if x != nil {
xt := evalStaticTypeOf(store, last, x)
checkIntegerType(xt)
checkIntegerKind(xt)
}
}

// assert that xt can be assigned as an integer type.
func checkIntegerType(xt Type) {
// assert that xt is a typed integer kind.
func checkIntegerKind(xt Type) {
switch xt.Kind() {
case IntKind, Int8Kind, Int16Kind, Int32Kind, Int64Kind,
UintKind, Uint8Kind, Uint16Kind, Uint32Kind, Uint64Kind,
BigintKind:
return // ok
default:
panic(fmt.Sprintf(
"expected integer type, but got %v",
"expected typed integer kind, but got %v",
xt.Kind()))
}
}
Expand Down
2 changes: 1 addition & 1 deletion gnovm/tests/files/for7.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ func main() {
}

// Error:
// main/files/for7.gno:4: cannot use int as bool
// main/files/for7.gno:4: expected typed bool kind, but got IntKind
2 changes: 1 addition & 1 deletion gnovm/tests/files/if2.gno
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ func main() {
}

// Error:
// main/files/if2.gno:7: cannot use int as bool
// main/files/if2.gno:7: expected typed bool kind, but got IntKind

0 comments on commit 71a298b

Please sign in to comment.