Detect timeouts

extensions
Volodymyr Shymanskyy 5 years ago
parent a49639db41
commit df838aacd5

@ -13,13 +13,9 @@
# - Fix "Empty Stack" check # - Fix "Empty Stack" check
# - Check Canonical NaN and Arithmetic NaN separately # - Check Canonical NaN and Arithmetic NaN separately
# - Fix names.wast # - Fix names.wast
# - Detect timeout (hangs)
import argparse import argparse
import os import os, sys, glob, time
import os.path
import glob
import sys
import json import json
import re import re
import struct import struct
@ -186,14 +182,15 @@ class Wasm3():
def __init__(self, executable): def __init__(self, executable):
self.exe = executable self.exe = executable
self.p = None self.p = None
self.timeout = 3.0
def load(self, wasm): def load(self, fn):
if self.p: if self.p:
self.terminate() self.terminate()
self.wasm = wasm self.loaded = fn
self.p = Popen( self.p = Popen(
[self.exe, "--repl", wasm], [self.exe, "--repl", fn],
shell = False, shell = False,
bufsize=0, stdin=PIPE, stdout=PIPE, stderr=STDOUT bufsize=0, stdin=PIPE, stdout=PIPE, stderr=STDOUT
) )
@ -212,26 +209,31 @@ class Wasm3():
cmd = " ".join(map(str, cmd)) + "\n" cmd = " ".join(map(str, cmd)) + "\n"
self._flush_input() self._flush_input()
self._write(cmd) self._write(cmd)
res = self._read_until("\nwasm3> ") return self._read_until("\nwasm3> ")
#print("INVOKE", cmd, "=>", res)
return res
def _read_until(self, token): def _read_until(self, token):
buff = "" buff = ""
while True: tout = time.time() + self.timeout
error = None
while time.time() < tout:
try: try:
data = self.q.get(timeout=0.2) data = self.q.get(timeout=0.1)
if data == None: if data == None:
error = "Crashed"
break break
buff = buff + data.decode("utf-8") buff = buff + data.decode("utf-8")
if token in buff: idx = buff.rfind(token)
return buff if idx >= 0:
return buff[0:idx]
except Empty: except Empty:
pass pass
else:
error = "Timeout"
# Crash => restart # Crash => restart
self.load(self.wasm) self.load(self.loaded)
raise Exception("Crashed") raise Exception(error)
def _write(self, data): def _write(self, data):
if not self._is_running(): if not self._is_running():
@ -282,10 +284,9 @@ blacklist = Blacklist([
"linking.wast:*", "linking.wast:*",
"exports.wast:*", "exports.wast:*",
"names.wast:*", "names.wast:*",
#"names.wast:608*",
]) ])
stats = dotdict(total_run=0, skipped=0, failed=0, crashed=0, success=0, missing=0) stats = dotdict(total_run=0, skipped=0, failed=0, crashed=0, timeout=0, success=0, missing=0)
# Convert some trap names from the original spec # Convert some trap names from the original spec
trapmap = { trapmap = {
@ -300,7 +301,7 @@ def runInvoke(test):
test.cmd.append(arg['value']) test.cmd.append(arg['value'])
displayArgs.append(formatValue(arg['value'], arg['type'])) displayArgs.append(formatValue(arg['value'], arg['type']))
test_id = f"{test.source} {' '.join(test.cmd)}" test_id = f"{test.source} -> {test.wasm} {' '.join(test.cmd)}"
if test_id in blacklist: if test_id in blacklist:
warning(f"Skipping {test_id}") warning(f"Skipping {test_id}")
stats.skipped += 1 stats.skipped += 1
@ -317,7 +318,7 @@ def runInvoke(test):
try: try:
output = wasm3.invoke(test.cmd).strip() output = wasm3.invoke(test.cmd).strip()
except Exception as e: except Exception as e:
stats.crashed += 1 output = ""
actual = f"<{e}>" actual = f"<{e}>"
# Parse the actual output # Parse the actual output
@ -340,6 +341,10 @@ def runInvoke(test):
if actual == "error no operation ()": if actual == "error no operation ()":
actual = "<Not Implemented>" actual = "<Not Implemented>"
stats.missing += 1 stats.missing += 1
elif actual == "<Crashed>":
stats.crashed += 1
elif actual == "<Timeout>":
stats.timeout += 1
# Prepare the expected result # Prepare the expected result
expect = None expect = None
@ -379,14 +384,13 @@ def runInvoke(test):
print(" ----------------------") print(" ----------------------")
print(f"Test: {ansi.HEADER}{test.source}{ansi.ENDC} -> {' '.join(test.cmd)}") print(f"Test: {ansi.HEADER}{test.source}{ansi.ENDC} -> {' '.join(test.cmd)}")
print(f"Args: {', '.join(displayArgs)}") print(f"Args: {', '.join(displayArgs)}")
#print(f"RetCode: {wasm3.returncode}")
print(f"Expected: {ansi.OKGREEN}{expect}{ansi.ENDC}") print(f"Expected: {ansi.OKGREEN}{expect}{ansi.ENDC}")
print(f"Actual: {ansi.WARNING}{actual}{ansi.ENDC}") print(f"Actual: {ansi.WARNING}{actual}{ansi.ENDC}")
if args.show_logs and len(output): if args.show_logs and len(output):
print(f"Log:") print(f"Log:")
print(output) print(output)
log.write(f"{test.source}\t|\t{filename(wasm)} {test.action.field}({', '.join(displayArgs)})\t=>\t\t") log.write(f"{test.source}\t|\t{test.wasm} {test.action.field}({', '.join(displayArgs)})\t=>\t\t")
if actual == expect or (expect == "<Anything>" and actual != "<Crashed>"): if actual == expect or (expect == "<Anything>" and actual != "<Crashed>"):
stats.success += 1 stats.success += 1
log.write(f"OK: {actual}\n") log.write(f"OK: {actual}\n")
@ -453,6 +457,7 @@ for fn in jsonFiles:
data = json.load(f) data = json.load(f)
wast_source = filename(data["source_filename"]) wast_source = filename(data["source_filename"])
wast_module = ""
print(f"Running {fn}") print(f"Running {fn}")
@ -460,13 +465,14 @@ for fn in jsonFiles:
test = dotdict() test = dotdict()
test.line = int(cmd["line"]) test.line = int(cmd["line"])
test.source = wast_source + ":" + str(test.line) test.source = wast_source + ":" + str(test.line)
test.wasm = wast_module
test.type = cmd["type"] test.type = cmd["type"]
if test.type == "module": if test.type == "module":
module = cmd["filename"] wast_module = cmd["filename"]
wasm = os.path.relpath(os.path.join(coreDir, module), curDir) fn = os.path.relpath(os.path.join(coreDir, wast_module), curDir)
wasm3.load(wasm) wasm3.load(fn)
elif ( test.type == "action" or elif ( test.type == "action" or
test.type == "assert_return" or test.type == "assert_return" or

Loading…
Cancel
Save