xgo/cmd/bench/main.go

220 lines
4.7 KiB
Go
Raw Normal View History

2019-01-09 10:17:42 +03:00
package main
import (
"fmt"
"time"
"github.com/d5/tengo/compiler"
2019-01-11 13:27:28 +03:00
"github.com/d5/tengo/compiler/ast"
"github.com/d5/tengo/compiler/parser"
"github.com/d5/tengo/compiler/source"
2019-01-09 10:17:42 +03:00
"github.com/d5/tengo/objects"
2019-01-11 13:27:28 +03:00
"github.com/d5/tengo/runtime"
2019-01-09 10:17:42 +03:00
)
func main() {
runFib(35)
runFibTC1(35)
runFibTC2(35)
}
2019-01-11 12:56:19 +03:00
func runFib(n int) {
start := time.Now()
2019-01-11 12:56:19 +03:00
nativeResult := fib(n)
nativeTime := time.Since(start)
input := `
2019-01-11 12:56:19 +03:00
fib := func(x) {
if x == 0 {
2019-01-11 12:56:19 +03:00
return 0
} else if x == 1 {
2019-01-11 12:56:19 +03:00
return 1
}
2019-01-13 22:10:55 +03:00
return fib(x-1) + fib(x-2)
}
2019-01-11 12:56:19 +03:00
` + fmt.Sprintf("out = fib(%d)", n)
parseTime, compileTime, runTime, result, err := runBench([]byte(input))
if err != nil {
panic(err)
}
if nativeResult != int(result.(*objects.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, int(result.(*objects.Int).Value)))
}
fmt.Println("-------------------------------------")
2019-01-11 12:56:19 +03:00
fmt.Printf("fibonacci(%d)\n", n)
fmt.Println("-------------------------------------")
2019-01-11 12:22:21 +03:00
fmt.Printf("Result: %d\n", nativeResult)
fmt.Printf("Go: %s\n", nativeTime)
fmt.Printf("Parser: %s\n", parseTime)
fmt.Printf("Compile: %s\n", compileTime)
fmt.Printf("VM: %s\n", runTime)
2019-01-09 10:17:42 +03:00
}
func runFibTC1(n int) {
2019-01-09 10:17:42 +03:00
start := time.Now()
nativeResult := fibTC1(n, 0)
nativeTime := time.Since(start)
input := `
fib := func(x, s) {
if x == 0 {
return 0 + s
} else if x == 1 {
return 1 + s
}
2019-01-13 22:10:55 +03:00
return fib(x-1, fib(x-2, s))
}
` + fmt.Sprintf("out = fib(%d, 0)", n)
parseTime, compileTime, runTime, result, err := runBench([]byte(input))
if err != nil {
panic(err)
}
if nativeResult != int(result.(*objects.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, int(result.(*objects.Int).Value)))
}
fmt.Println("-------------------------------------")
fmt.Printf("fibonacci(%d) (tail-call #1)\n", n)
fmt.Println("-------------------------------------")
fmt.Printf("Result: %d\n", nativeResult)
fmt.Printf("Go: %s\n", nativeTime)
fmt.Printf("Parser: %s\n", parseTime)
fmt.Printf("Compile: %s\n", compileTime)
fmt.Printf("VM: %s\n", runTime)
}
func runFibTC2(n int) {
start := time.Now()
nativeResult := fibTC2(n, 0, 1)
2019-01-09 10:17:42 +03:00
nativeTime := time.Since(start)
input := `
2019-01-11 12:56:19 +03:00
fib := func(x, a, b) {
2019-01-11 01:51:20 +03:00
if x == 0 {
2019-01-11 12:56:19 +03:00
return a
2019-01-11 01:51:20 +03:00
} else if x == 1 {
2019-01-11 12:56:19 +03:00
return b
2019-01-09 10:17:42 +03:00
}
2019-01-13 22:10:55 +03:00
return fib(x-1, b, a+b)
2019-01-09 10:17:42 +03:00
}
2019-01-11 12:56:19 +03:00
` + fmt.Sprintf("out = fib(%d, 0, 1)", n)
2019-01-09 10:17:42 +03:00
parseTime, compileTime, runTime, result, err := runBench([]byte(input))
if err != nil {
panic(err)
}
if nativeResult != int(result.(*objects.Int).Value) {
panic(fmt.Errorf("wrong result: %d != %d", nativeResult, int(result.(*objects.Int).Value)))
}
fmt.Println("-------------------------------------")
fmt.Printf("fibonacci(%d) (tail-call #2)\n", n)
2019-01-11 01:51:20 +03:00
fmt.Println("-------------------------------------")
2019-01-11 12:22:21 +03:00
fmt.Printf("Result: %d\n", nativeResult)
2019-01-09 10:17:42 +03:00
fmt.Printf("Go: %s\n", nativeTime)
fmt.Printf("Parser: %s\n", parseTime)
fmt.Printf("Compile: %s\n", compileTime)
fmt.Printf("VM: %s\n", runTime)
}
func fib(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fib(n-1) + fib(n-2)
}
}
func fibTC1(n, s int) int {
if n == 0 {
return 0 + s
} else if n == 1 {
return 1 + s
}
return fibTC1(n-1, fibTC1(n-2, s))
}
func fibTC2(n, a, b int) int {
if n == 0 {
2019-01-11 12:56:19 +03:00
return a
} else if n == 1 {
2019-01-11 12:56:19 +03:00
return b
} else {
return fibTC2(n-1, b, a+b)
}
}
2019-01-09 10:17:42 +03:00
func runBench(input []byte) (parseTime time.Duration, compileTime time.Duration, runTime time.Duration, result objects.Object, err error) {
var astFile *ast.File
parseTime, astFile, err = parse(input)
if err != nil {
return
}
var bytecode *compiler.Bytecode
compileTime, bytecode, err = compileFile(astFile)
if err != nil {
return
}
runTime, result, err = runVM(bytecode)
return
}
func parse(input []byte) (time.Duration, *ast.File, error) {
fileSet := source.NewFileSet()
inputFile := fileSet.AddFile("bench", -1, len(input))
2019-01-09 10:17:42 +03:00
start := time.Now()
p := parser.NewParser(inputFile, input, nil)
file, err := p.ParseFile()
2019-01-09 10:17:42 +03:00
if err != nil {
return time.Since(start), nil, err
}
return time.Since(start), file, nil
}
func compileFile(file *ast.File) (time.Duration, *compiler.Bytecode, error) {
symTable := compiler.NewSymbolTable()
symTable.Define("out")
start := time.Now()
c := compiler.NewCompiler(file.InputFile, symTable, nil, nil, nil)
2019-01-09 10:17:42 +03:00
if err := c.Compile(file); err != nil {
return time.Since(start), nil, err
}
bytecode := c.Bytecode()
bytecode.RemoveDuplicates()
return time.Since(start), bytecode, nil
2019-01-09 10:17:42 +03:00
}
func runVM(bytecode *compiler.Bytecode) (time.Duration, objects.Object, error) {
2019-01-11 13:27:28 +03:00
globals := make([]*objects.Object, runtime.GlobalsSize)
2019-01-09 10:17:42 +03:00
start := time.Now()
v := runtime.NewVM(bytecode, globals, nil, nil, -1)
2019-01-09 10:17:42 +03:00
if err := v.Run(); err != nil {
return time.Since(start), nil, err
}
return time.Since(start), *globals[0], nil
}