Browse Source

WIP on testing: 00e6db4 Add instantiate which immediately fixes the location of the new elements

Yentl Van Tendeloo 8 years ago
parent
commit
b698243fcb

+ 1 - 0
bootstrap/bootstrap.py

@@ -105,6 +105,7 @@ def bootstrap():
                     "log": ["String", "String"],
                     "time": ["Float"],
                     "hash": ["String", "String"],
+                    "__sleep": ["Float", "Float"],
                 }
 
     jit_primitives = {

+ 5 - 0
bootstrap/primitives.alc

@@ -82,6 +82,11 @@ Boolean function is_physical_boolean(a: Element) = ?primitives/is_physical_boole
 Boolean function is_physical_action(a: Element) = ?primitives/is_physical_action
 Float function time() = ?primitives/time
 String function hash(a : String) = ?primitives/hash
+Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep
+
+Float function sleep(a : Float):
+	__sleep(a, False)
+	return a!
 
 Element function exec(first_instr : Element):
 	// This does very ugly things, so beware!

+ 0 - 8
bootstrap/utils.alc

@@ -54,14 +54,6 @@ String function JSON_print(model : Element):
 	result = result + "]"
 	return result!
 
-Void function sleep(timeout : Float):
-	// TODO Placeholder function for a real sleep operation
-	Float start
-	start = time()
-	while (time() < (start + timeout)):
-		continue!
-	return!
-
 Element function input_timeout(timeout : Float):
 	Float start
 	start = time()

+ 113 - 77
hybrid_server/classes/task.xml

@@ -11,11 +11,11 @@
             self.taskname = taskname
             self.mvs_operations = mvs_operations
             self.mvk = mvk
+            self.unlocked = True
 
-            self.failed = False
+            self.input_queue = []
             self.output_queue = []
             self.outputs = []
-            self.do_yield = False
             ]]>
         </body>
 
@@ -37,91 +37,27 @@
                     if commands is None:
                         break
                     reply = [mvs_operations[command[0]](*(command[1])) for command in commands]
+                return (0.0, False)
+            except SleepKernel as e:
+                print("Got sleep for: " + str(e.timeout))
+                return (e.timeout, False)
             except:
                 import traceback
                 print(traceback.format_exc())
-                #TODO delete self, as the task has crashed!
-                return False
-            return True
+                return (float('inf'), False)
             ]]>
         </body>
     </method>
 
-    <scxml initial="start">
-        <parallel id="start">
-            <state id="execution" initial="running">
-                <state id="running" initial="executing">
-                    <transition event="pause_task" target="../suspended"/>
-
-                    <state id="executing">
-                        <onentry>
-                            <script>
-                                start_time = time.time()
-                                # Grant each task some milliseconds of execution
-                                self.do_yield = False
-                                while (time.time() - start_time &lt; 0.05):
-                                    if not self.execute_modelverse(self.taskname, "execute_rule", []):
-                                        # Failed!
-                                        self.failed = True
-                                        break
-
-                                    if not self.mvk.success:
-                                        # Blocking or broken, so quit already to stop wasting CPU
-                                        self.do_yield = True
-                                        break
-
-                                if not self.failed:
-                                    # Perform output if there is anything
-                                    while self.output_queue:
-                                        if self.execute_modelverse(self.taskname, "get_output", []):
-                                            if self.mvk.success:
-                                                self.outputs.append((self.output_queue.pop(0), self.mvk.returnvalue))
-                                            else:
-                                                # No output left in Mv, so break
-                                                break
-                                        else:
-                                            self.failed = True
-                                            break
-                            </script>
-                        </onentry>
-
-                        <transition cond="self.failed" target="../../failed"/>
-                        <transition after="self.sccd_yield()" target="."/>
-                        <transition cond="self.do_yield" target="../yielded"/>
-                    </state>
-
-                    <state id="yielded">
-                        <transition after="self.sccd_yield() + 1" target="../executing"/>
-                        <transition event="processed_input" target="../executing"/>
-                        <transition event="waiting_output" target="../executing"/>
-                    </state>
-                </state>
-
-                <state id="suspended">
-                    <state id="suspended">
-                        <transition event="resume" target="../../running"/>
-                    </state>
-                </state>
-
-                <state id="failed">
-                    <state id="failed">
-                        <!-- TODO delete task -->
-                    </state>
-                </state>
-            </state>
-
-            <state id="process_events">
-                <state id="process_events">
+    <scxml initial="main">
+        <parallel id="main">
+            <state id="queue">
+                <state id="queue">
                     <transition event="input" target=".">
                         <parameter name="params"/>
                         <script>
-                            for args_entry in params:
-                                if not self.execute_modelverse(self.taskname, "set_input", [args_entry]):
-                                    # Failed!
-                                    self.failed = True
-                                    break
+                            self.input_queue.extend(params)
                         </script>
-                        <raise event="processed_input"/>
                     </transition>
 
                     <transition event="output" target=".">
@@ -129,7 +65,6 @@
                         <script>
                             self.output_queue.append(params)
                         </script>
-                        <raise event="waiting_output"/>
                     </transition>
 
                     <transition cond="self.outputs" target=".">
@@ -142,6 +77,107 @@
                     </transition>
                 </state>
             </state>
+
+            <state id="process" initial="running">
+                <state id="running" initial="components">
+                    <transition event="suspend" target="../suspended"/>
+
+                    <history id="history" type="deep"/>
+
+                    <parallel id="components">
+                        <state id="input">
+                            <state id="input">
+                                <transition cond="self.input_queue" target=".">
+                                    <script>
+                                        for args_entry in self.input_queue:
+                                            self.execute_modelverse(self.taskname, "set_input", [args_entry])
+                                        self.input_queue = []
+                                    </script>
+                                    <raise event="wake_timer"/>
+                                </transition>
+                            </state>
+                        </state>
+
+                        <state id="processing" initial="processing">
+                            <state id="processing">
+                                <onentry>
+                                    <script>
+                                        start_time = time.time()
+                                        # Grant each task some milliseconds of execution
+                                        while (time.time() - start_time &lt; 0.05):
+                                            timeout = self.execute_modelverse(self.taskname, "execute_rule", [])
+                                            if timeout[0] > 0.0:
+                                                # We should not continue immediately
+                                                break
+                                        self.timeout = timeout
+                                    </script>
+                                </onentry>
+
+                                <transition cond="self.timeout[0] == 0.0" after="self.sccd_yield()" target="."/>
+                                <transition cond="0.0 &lt; self.timeout[0] &lt; float('inf')" after="self.sccd_yield()" target="../blocked">
+                                    <script>
+                                        self.unlocked = False
+                                    </script>
+                                    <raise event="start_timer">
+                                        <parameter expr="self.timeout[0]"/>
+                                        <parameter expr="self.timeout[1]"/>
+                                    </raise>
+                                </transition>
+                                <transition cond="self.timeout[0] == float('inf')" target="../failed"/>
+                            </state>
+
+                            <state id="blocked">
+                                <transition cond="self.unlocked" target="../processing"/>
+                            </state>
+
+                            <state id="failed">
+                                <script>
+                                    print("TODO: task has failed")
+                                </script>
+                            </state>
+                        </state>
+
+                        <state id="output">
+                            <state id="output">
+                                <onentry>
+                                    <script>
+                                        if self.output_queue:
+                                            if self.execute_modelverse(self.taskname, "get_output", []):
+                                                self.outputs.append((self.output_queue.pop(0), self.mvk.returnvalue))
+                                    </script>
+                                </onentry>
+                            </state>
+                        </state>
+                    </parallel>
+                </state>
+
+                <state id="suspended">
+                    <transition event="resume" target="../running/history"/>
+                </state>
+            </state>
+
+            <state id="timer" initial="ready">
+                <state id="waiting">
+                    <transition after="self.sccd_yield() + self.timer_duration" target="../ready"/>
+                    <transition event="wake_timer" cond="self.interruptable" target="../ready"/>
+                </state>
+
+                <state id="ready">
+                    <onentry>
+                        <script>
+                            self.unlocked = True
+                        </script>
+                    </onentry>
+                    <transition event="start_timer" target="../waiting">
+                        <parameter name="duration"/>
+                        <parameter name="interruptable"/>
+                        <script>
+                            self.timer_duration = duration
+                            self.interruptable = interruptable
+                        </script>
+                    </transition>
+                </state>
+            </state>
         </parallel>
     </scxml>
 </class>

+ 1 - 0
hybrid_server/server.xml

@@ -15,6 +15,7 @@
         from collections import defaultdict
         sys.path.append("../kernel/")
         sys.path.append("../state/")
+        from modelverse_kernel.primitives import SleepKernel
         from modelverse_kernel.main import ModelverseKernel
         from modelverse_kernel.legacy import ModelverseKernel as LegacyModelverseKernel
         from modelverse_state.main import ModelverseState

+ 3 - 3
interface/HUTN/hutn_compiler/primitives_visitor.py

@@ -215,7 +215,7 @@ class PrimitivesVisitor(Visitor):
 
     def visit_lvalue(self, tree):
         symbol = self.get_symbol(tree)
-        if symbol.name in ["input", "output"]:
+        if symbol.name in ["__input", "__output"]:
             return
         r = self.value(Action("resolve"))
         # print symbol.name, symbol.is_func(), symbol.node
@@ -343,7 +343,7 @@ class PrimitivesVisitor(Visitor):
 
     def pre_visit_funcdecl(self, tree):
         symbol = self.get_symbol(tree)
-        if symbol.name in ["input", "output"]:
+        if symbol.name in ["__input", "__output"]:
             return
 
         # TODO: fix funcdecl special case: "X function f(...) = ..."
@@ -374,7 +374,7 @@ class PrimitivesVisitor(Visitor):
 
     def visit_funcdecl(self, tree):
         symbol = self.get_symbol(tree)
-        if symbol.name in ["input", "output"]:
+        if symbol.name in ["__input", "__output"]:
             return
 
         func_body = tree.get_child("func_body")

+ 1 - 0
interface/HUTN/includes/primitives.alh

@@ -92,6 +92,7 @@ Boolean function is_physical_boolean(a : Element)
 Boolean function has_value(a : Element)
 Float function time()
 String function hash(a : String)
+Float function sleep(a : Float)
 
 Element function exec(a : Element)
 Element function resolve(var_name : String)

+ 1 - 0
kernel/modelverse_jit/runtime.py

@@ -178,6 +178,7 @@ def unreachable():
 
 def get_input(**parameters):
     """Retrieves input."""
+    print("EXECUTED")
     mvk = parameters["mvk"]
     task_root = parameters["task_root"]
     while 1:

+ 11 - 19
kernel/modelverse_kernel/main.py

@@ -18,7 +18,6 @@ class ModelverseKernel(object):
     def __init__(self, root):
         self.root = root
         self.returnvalue = None
-        self.success = True
         # request_handlers is a dictionary of tasknames to dictionaries of operations
         # to request handlers. In generics notation:
         #
@@ -92,28 +91,21 @@ class ModelverseKernel(object):
         self.debug_info = defaultdict(list)
 
     def execute_yields(self, taskname, operation, params, reply):
-        try:
-            self.success = True
-            self.taskname = taskname
-            if taskname not in self.request_handlers:
-                self.request_handlers[taskname] = {}
-            if operation not in self.request_handlers[taskname]:
-                # Create the generator for the function to execute
-                self.request_handlers[taskname][operation] = RequestHandler()
-            handler = self.request_handlers[taskname][operation]
-            if not handler.is_active():
-                handler.push_generator(getattr(self, operation)(taskname, *params))
-
-            return handler.handle_request(reply)
-        except:
-            print("Unknown error @ " + str(self.debug_info.get(taskname, "Unknown task")))
-            raise
+        self.taskname = taskname
+        if taskname not in self.request_handlers:
+            self.request_handlers[taskname] = {}
+        if operation not in self.request_handlers[taskname]:
+            # Create the generator for the function to execute
+            self.request_handlers[taskname][operation] = RequestHandler()
+        handler = self.request_handlers[taskname][operation]
+        if not handler.is_active():
+            handler.push_generator(getattr(self, operation)(taskname, *params))
+
+        return handler.handle_request(reply)
 
     def execute_rule(self, taskname):
         task_root, =    yield [("RD", [self.root, taskname])]
         if task_root is None:
-            self.success = False
-            self.returnvalue = None
             yield None
         else:
             task_frame, = yield [("RD", [task_root, "frame"])]

+ 11 - 0
kernel/modelverse_kernel/primitives.py

@@ -13,6 +13,12 @@ class InterpretedFunctionFinished(Exception):
         Exception.__init__(self)
         self.result = value
 
+class SleepKernel(Exception):
+    """Exception to indicate the kernel to sleep for some time."""
+    def __init__(self, timeout):
+        Exception.__init__(self)
+        self.timeout = timeout
+
 # Functions annotated with __exception_return use the JIT's calling convention instead of
 # the kernel's: returns are handled by throwing a PrimitiveFinished exception; the caller's
 # returnvalue is not modified.
@@ -527,3 +533,8 @@ def hash(a, **remainder):
     b_value = hashlib.sha512(a_value).hexdigest()
     b, = yield [("CNV", [b_value])]
     raise PrimitiveFinished(b)
+
+def __sleep(a, b, **remainder):
+    timeout, interruptable = yield [("RV", [a]), ("RV", [b])]
+    yield [("SLEEP", [timeout, interruptable])]
+    raise PrimitiveFinished(a)

+ 7 - 1
kernel/modelverse_kernel/request_handler.py

@@ -45,7 +45,8 @@ class RequestHandler(object):
             'TRY' : self.execute_try,
             'CATCH' : self.execute_catch,
             'END_TRY' : self.execute_end_try,
-            'DEBUG_INFO' : self.execute_debug_info
+            'DEBUG_INFO' : self.execute_debug_info,
+            'SLEEP' : self.execute_sleep,
         }
 
     def is_active(self):
@@ -370,3 +371,8 @@ class RequestHandler(object):
         top_entry = self.generator_stack[-1]
         top_entry["function_name"], top_entry["source_map"], top_entry["function_origin"] = request_args
         self.append_reply(None)
+
+    def execute_sleep(self, request_args):
+        """Executes a SLEEP-request with the given argument list."""
+        self.append_reply(None)
+        raise primitive_functions.SleepKernel(request_args[0])

+ 1 - 1
scripts/run_fast_tests.py

@@ -7,4 +7,4 @@ subprocess.check_call([sys.executable, "-m", "pytest"], cwd="kernel")
 
 subprocess.check_call([sys.executable, "-m", "pytest"], cwd="interface/HUTN")
 
-subprocess.check_call([sys.executable, "-m", "pytest", "integration", "--runslow"])
+subprocess.check_call([sys.executable, "-m", "pytest", "integration"])