make interp timeout configurable from command line
Этот коммит содержится в:
родитель
a4ee98e0e1
коммит
0b77e92c50
7 изменённых файлов: 34 добавлений и 28 удалений
|
@ -431,7 +431,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||||
if pkgInit.IsNil() {
|
if pkgInit.IsNil() {
|
||||||
panic("init not found for " + pkg.Pkg.Path())
|
panic("init not found for " + pkg.Pkg.Path())
|
||||||
}
|
}
|
||||||
err := interp.RunFunc(pkgInit, config.DumpSSA())
|
err := interp.RunFunc(pkgInit, config.Options.InterpTimeout, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1055,7 +1055,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
|
||||||
// needed to convert a program to its final form. Some transformations are not
|
// needed to convert a program to its final form. Some transformations are not
|
||||||
// optional and must be run as the compiler expects them to run.
|
// optional and must be run as the compiler expects them to run.
|
||||||
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
||||||
err := interp.Run(mod, config.DumpSSA())
|
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -29,6 +30,7 @@ type Options struct {
|
||||||
Scheduler string
|
Scheduler string
|
||||||
Serial string
|
Serial string
|
||||||
Work bool // -work flag to print temporary build directory
|
Work bool // -work flag to print temporary build directory
|
||||||
|
InterpTimeout time.Duration
|
||||||
PrintIR bool
|
PrintIR bool
|
||||||
DumpSSA bool
|
DumpSSA bool
|
||||||
VerifyIR bool
|
VerifyIR bool
|
||||||
|
|
|
@ -30,10 +30,11 @@ type runner struct {
|
||||||
objects []object // slice of objects in memory
|
objects []object // slice of objects in memory
|
||||||
globals map[llvm.Value]int // map from global to index in objects slice
|
globals map[llvm.Value]int // map from global to index in objects slice
|
||||||
start time.Time
|
start time.Time
|
||||||
|
timeout time.Duration
|
||||||
callsExecuted uint64
|
callsExecuted uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRunner(mod llvm.Module, debug bool) *runner {
|
func newRunner(mod llvm.Module, timeout time.Duration, debug bool) *runner {
|
||||||
r := runner{
|
r := runner{
|
||||||
mod: mod,
|
mod: mod,
|
||||||
targetData: llvm.NewTargetData(mod.DataLayout()),
|
targetData: llvm.NewTargetData(mod.DataLayout()),
|
||||||
|
@ -42,6 +43,7 @@ func newRunner(mod llvm.Module, debug bool) *runner {
|
||||||
objects: []object{{}},
|
objects: []object{{}},
|
||||||
globals: make(map[llvm.Value]int),
|
globals: make(map[llvm.Value]int),
|
||||||
start: time.Now(),
|
start: time.Now(),
|
||||||
|
timeout: timeout,
|
||||||
}
|
}
|
||||||
r.pointerSize = uint32(r.targetData.PointerSize())
|
r.pointerSize = uint32(r.targetData.PointerSize())
|
||||||
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
|
r.i8ptrType = llvm.PointerType(mod.Context().Int8Type(), 0)
|
||||||
|
@ -58,8 +60,8 @@ func (r *runner) dispose() {
|
||||||
|
|
||||||
// Run evaluates runtime.initAll function as much as possible at compile time.
|
// Run evaluates runtime.initAll function as much as possible at compile time.
|
||||||
// Set debug to true if it should print output while running.
|
// Set debug to true if it should print output while running.
|
||||||
func Run(mod llvm.Module, debug bool) error {
|
func Run(mod llvm.Module, timeout time.Duration, debug bool) error {
|
||||||
r := newRunner(mod, debug)
|
r := newRunner(mod, timeout, debug)
|
||||||
defer r.dispose()
|
defer r.dispose()
|
||||||
|
|
||||||
initAll := mod.NamedFunction("runtime.initAll")
|
initAll := mod.NamedFunction("runtime.initAll")
|
||||||
|
@ -199,10 +201,10 @@ func Run(mod llvm.Module, debug bool) error {
|
||||||
|
|
||||||
// RunFunc evaluates a single package initializer at compile time.
|
// RunFunc evaluates a single package initializer at compile time.
|
||||||
// Set debug to true if it should print output while running.
|
// Set debug to true if it should print output while running.
|
||||||
func RunFunc(fn llvm.Value, debug bool) error {
|
func RunFunc(fn llvm.Value, timeout time.Duration, debug bool) error {
|
||||||
// Create and initialize *runner object.
|
// Create and initialize *runner object.
|
||||||
mod := fn.GlobalParent()
|
mod := fn.GlobalParent()
|
||||||
r := newRunner(mod, debug)
|
r := newRunner(mod, timeout, debug)
|
||||||
defer r.dispose()
|
defer r.dispose()
|
||||||
initName := fn.Name()
|
initName := fn.Name()
|
||||||
if !strings.HasSuffix(initName, ".init") {
|
if !strings.HasSuffix(initName, ".init") {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
@ -52,7 +53,7 @@ func runTest(t *testing.T, pathPrefix string) {
|
||||||
defer mod.Dispose()
|
defer mod.Dispose()
|
||||||
|
|
||||||
// Perform the transform.
|
// Perform the transform.
|
||||||
err = Run(mod, false)
|
err = Run(mod, 10*time.Minute, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err, match := err.(*Error); match {
|
if err, match := err.(*Error); match {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
|
|
|
@ -17,8 +17,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||||
locals := make([]value, len(fn.locals))
|
locals := make([]value, len(fn.locals))
|
||||||
r.callsExecuted++
|
r.callsExecuted++
|
||||||
|
|
||||||
t0 := time.Since(r.start)
|
|
||||||
|
|
||||||
// Parameters are considered a kind of local values.
|
// Parameters are considered a kind of local values.
|
||||||
for i, param := range params {
|
for i, param := range params {
|
||||||
locals[i] = param
|
locals[i] = param
|
||||||
|
@ -143,11 +141,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||||
}
|
}
|
||||||
switch inst.opcode {
|
switch inst.opcode {
|
||||||
case llvm.Ret:
|
case llvm.Ret:
|
||||||
const maxInterpSeconds = 180
|
if time.Since(r.start) > r.timeout {
|
||||||
if t0 > maxInterpSeconds*time.Second {
|
// Running for more than the allowed timeout; This shouldn't happen, but it does.
|
||||||
// Running for more than maxInterpSeconds seconds. This should never happen, but does.
|
|
||||||
// See github.com/tinygo-org/tinygo/issues/2124
|
// See github.com/tinygo-org/tinygo/issues/2124
|
||||||
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %d seconds, timing out (executed calls: %d)", maxInterpSeconds, r.callsExecuted))
|
return nil, mem, r.errorAt(fn.blocks[0].instructions[0], fmt.Errorf("interp: running for more than %s, timing out (executed calls: %d)", r.timeout, r.callsExecuted))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(operands) != 0 {
|
if len(operands) != 0 {
|
||||||
|
|
2
main.go
2
main.go
|
@ -1295,6 +1295,7 @@ func main() {
|
||||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
scheduler := flag.String("scheduler", "", "which scheduler to use (none, tasks, asyncify)")
|
||||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||||
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
||||||
|
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
||||||
printIR := flag.Bool("printir", false, "print LLVM IR")
|
printIR := flag.Bool("printir", false, "print LLVM IR")
|
||||||
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
||||||
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
||||||
|
@ -1385,6 +1386,7 @@ func main() {
|
||||||
Scheduler: *scheduler,
|
Scheduler: *scheduler,
|
||||||
Serial: *serial,
|
Serial: *serial,
|
||||||
Work: *work,
|
Work: *work,
|
||||||
|
InterpTimeout: *interpTimeout,
|
||||||
PrintIR: *printIR,
|
PrintIR: *printIR,
|
||||||
DumpSSA: *dumpSSA,
|
DumpSSA: *dumpSSA,
|
||||||
VerifyIR: *verifyIR,
|
VerifyIR: *verifyIR,
|
||||||
|
|
30
main_test.go
30
main_test.go
|
@ -275,14 +275,15 @@ func emuCheck(t *testing.T, options compileopts.Options) {
|
||||||
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
||||||
return compileopts.Options{
|
return compileopts.Options{
|
||||||
// GOOS/GOARCH are only used if target == ""
|
// GOOS/GOARCH are only used if target == ""
|
||||||
GOOS: goenv.Get("GOOS"),
|
GOOS: goenv.Get("GOOS"),
|
||||||
GOARCH: goenv.Get("GOARCH"),
|
GOARCH: goenv.Get("GOARCH"),
|
||||||
GOARM: goenv.Get("GOARM"),
|
GOARM: goenv.Get("GOARM"),
|
||||||
Target: target,
|
Target: target,
|
||||||
Semaphore: sema,
|
Semaphore: sema,
|
||||||
Debug: true,
|
InterpTimeout: 180 * time.Second,
|
||||||
VerifyIR: true,
|
Debug: true,
|
||||||
Opt: "z",
|
VerifyIR: true,
|
||||||
|
Opt: "z",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,12 +293,13 @@ func optionsFromTarget(target string, sema chan struct{}) compileopts.Options {
|
||||||
func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
|
func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options {
|
||||||
parts := strings.Split(osarch, "/")
|
parts := strings.Split(osarch, "/")
|
||||||
options := compileopts.Options{
|
options := compileopts.Options{
|
||||||
GOOS: parts[0],
|
GOOS: parts[0],
|
||||||
GOARCH: parts[1],
|
GOARCH: parts[1],
|
||||||
Semaphore: sema,
|
Semaphore: sema,
|
||||||
Debug: true,
|
InterpTimeout: 180 * time.Second,
|
||||||
VerifyIR: true,
|
Debug: true,
|
||||||
Opt: "z",
|
VerifyIR: true,
|
||||||
|
Opt: "z",
|
||||||
}
|
}
|
||||||
if options.GOARCH == "arm" {
|
if options.GOARCH == "arm" {
|
||||||
options.GOARM = parts[2]
|
options.GOARM = parts[2]
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче