|
@@ -1,262 +1,265 @@
|
|
|
-<class name="MvKController">
|
|
|
- <relationships>
|
|
|
- <association name="to_mvi" class="Server" min="1" max="1"/>
|
|
|
- </relationships>
|
|
|
- <constructor>
|
|
|
- <parameter name="params"/>
|
|
|
- <body>
|
|
|
- <![CDATA[
|
|
|
- self.mvs = ModelverseState("../bootstrap/bootstrap.m.gz")
|
|
|
- # Enable Garbage Collection
|
|
|
- self.mvs.GC = True
|
|
|
- self.root = self.mvs.read_root()[0]
|
|
|
-
|
|
|
- # Instantiate the kernel.
|
|
|
- default_kernel_type = 'jit'
|
|
|
- kernel_type = default_kernel_type
|
|
|
- for parameter in params:
|
|
|
- if parameter.startswith('--kernel='):
|
|
|
- kernel_type = parameter[len('--kernel='):]
|
|
|
-
|
|
|
- if kernel_type == 'legacy-interpreter':
|
|
|
- self.mvk = LegacyModelverseKernel(self.root)
|
|
|
- elif kernel_type == 'interpreter':
|
|
|
- self.mvk = ModelverseKernel(self.root)
|
|
|
- self.mvk.jit.set_jit_enabled(False)
|
|
|
- else:
|
|
|
- assert kernel_type == default_kernel_type
|
|
|
- self.mvk = ModelverseKernel(self.root)
|
|
|
-
|
|
|
- self.all_failed = False
|
|
|
- self.timeout = False
|
|
|
- self.init_time = time.time()
|
|
|
-
|
|
|
- self.users = set()
|
|
|
- self.input_queue = defaultdict(list)
|
|
|
- self.output_queue = defaultdict(list)
|
|
|
- self.source = None
|
|
|
- self.port = int(sys.argv[1])
|
|
|
- self.count = 0
|
|
|
-
|
|
|
- self.debugged_users = set()
|
|
|
- self.debug_info = {}
|
|
|
- self.done_something = False
|
|
|
-
|
|
|
- self.mvs_operations = {
|
|
|
- "CN": self.mvs.create_node,
|
|
|
- "CE": self.mvs.create_edge,
|
|
|
- "CNV": self.mvs.create_nodevalue,
|
|
|
- "CD": self.mvs.create_dict,
|
|
|
-
|
|
|
- "RV": self.mvs.read_value,
|
|
|
- "RO": self.mvs.read_outgoing,
|
|
|
- "RI": self.mvs.read_incoming,
|
|
|
- "RE": self.mvs.read_edge,
|
|
|
- "RD": self.mvs.read_dict,
|
|
|
- "RDN": self.mvs.read_dict_node,
|
|
|
- "RDNE": self.mvs.read_dict_node_edge,
|
|
|
- "RDE": self.mvs.read_dict_edge,
|
|
|
- "RRD": self.mvs.read_reverse_dict,
|
|
|
- "RR": self.mvs.read_root,
|
|
|
- "RDK": self.mvs.read_dict_keys,
|
|
|
-
|
|
|
- "DE": self.mvs.delete_edge,
|
|
|
- "DN": self.mvs.delete_node,
|
|
|
- }
|
|
|
-
|
|
|
- self.execute_modelverse("", "load_primitives", [])
|
|
|
- ]]>
|
|
|
- </body>
|
|
|
- </constructor>
|
|
|
-
|
|
|
- <method name="execute_modelverse">
|
|
|
- <parameter name="username"/>
|
|
|
- <parameter name="operation"/>
|
|
|
- <parameter name="params"/>
|
|
|
- <body>
|
|
|
- <![CDATA[
|
|
|
- reply = None
|
|
|
- commands = []
|
|
|
- while 1:
|
|
|
- commands = self.mvk.execute_yields(username, operation, params, reply)
|
|
|
- if commands is None:
|
|
|
- break
|
|
|
- reply = [self.mvs_operations[command[0]](*(command[1]))[0] for command in commands]
|
|
|
- #for c, r in zip(commands, reply):
|
|
|
- # print("%s --> %s" % (c, r))
|
|
|
- ]]>
|
|
|
- </body>
|
|
|
- </method>
|
|
|
-
|
|
|
- <scxml initial="init_server">
|
|
|
- <state id="init_server">
|
|
|
- <onentry>
|
|
|
- <raise scope="cd" event="create_instance">
|
|
|
- <parameter expr="'to_mvi'"/>
|
|
|
- <parameter expr="'Server'"/>
|
|
|
- <parameter expr="''"/>
|
|
|
- <parameter expr="self.port"/>
|
|
|
- </raise>
|
|
|
- </onentry>
|
|
|
- <transition event="instance_created" target="../running">
|
|
|
- <parameter name="instancename"/>
|
|
|
- <raise scope="cd" event="start_instance">
|
|
|
- <parameter expr="instancename"/>
|
|
|
- </raise>
|
|
|
- </transition>
|
|
|
- </state>
|
|
|
-
|
|
|
- <parallel id="running">
|
|
|
- <state id="wait_for_requests">
|
|
|
- <state id="wait">
|
|
|
- <transition event="from_mvi" target=".">
|
|
|
- <parameter name="source"/>
|
|
|
- <parameter name="data"/>
|
|
|
- <script>
|
|
|
- # No JSON encoding necessary, as it is not complex
|
|
|
- try:
|
|
|
- self.done_something = False
|
|
|
- if data["op"] == "set_input":
|
|
|
- if "value" in data:
|
|
|
- value = [json.loads(data["value"])]
|
|
|
- else:
|
|
|
- value = json.loads(data["data"])
|
|
|
- self.input_queue[data["username"]].append((source, value))
|
|
|
- elif data["op"] == "get_output":
|
|
|
- self.output_queue[data["username"]].append(source)
|
|
|
- elif data["op"] == "attach_debugger":
|
|
|
- self.debugged_users.add(data["username"])
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- self.debug_info[data["username"]] = {'state': 'running', 'breakpoints': []}
|
|
|
- elif data["op"] == "detach_debugger":
|
|
|
- self.debugged_users.discard(data["username"])
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- del self.debug_info[data["username"]]
|
|
|
- elif data["op"] == "pause":
|
|
|
- if data["username"] in self.debugged_users:
|
|
|
- self.debug_info[data["username"]]['state'] = 'paused'
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- elif data["op"] == "resume":
|
|
|
- if data["username"] in self.debugged_users:
|
|
|
- self.debug_info[data["username"]]['state'] = 'running'
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- elif data["op"] == "step_over":
|
|
|
- pass
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- elif data["op"] == "step_into":
|
|
|
- pass
|
|
|
- self.done_something = True
|
|
|
- self.source = source
|
|
|
- else:
|
|
|
- raise Exception("DROPPING unknown operation: " + str(data["op"]))
|
|
|
- except ValueError:
|
|
|
- print("Error when deserializing request: " + str(data))
|
|
|
- raise
|
|
|
- </script>
|
|
|
- </transition>
|
|
|
-
|
|
|
- <transition cond="self.done_something" target=".">
|
|
|
- <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.source">
|
|
|
- <parameter expr="json.dumps(True)"/>
|
|
|
- </raise>
|
|
|
- <script>
|
|
|
- self.done_something = False
|
|
|
- </script>
|
|
|
- </transition>
|
|
|
- </state>
|
|
|
- </state>
|
|
|
-
|
|
|
- <state id="execution">
|
|
|
- <state id="execution">
|
|
|
- <onentry>
|
|
|
- <script>
|
|
|
- self.timeout = False
|
|
|
- self.destination = None
|
|
|
- if self.users:
|
|
|
- user = self.users.pop()
|
|
|
- if not user in self.debugged_users or self.debug_info[user]['state'] == 'running':
|
|
|
- # Check if there are values to input
|
|
|
- if self.input_queue[user]:
|
|
|
- source, args = self.input_queue[user].pop(0)
|
|
|
- for args_entry in args:
|
|
|
- self.execute_modelverse(user, "set_input", [args_entry])
|
|
|
-
|
|
|
- self.destination = source
|
|
|
- self.value = "OK"
|
|
|
- self.all_failed = False
|
|
|
-
|
|
|
- nr_of_steps = 1 if user in self.debugged_users else 100
|
|
|
- # Now process for some steps, or until we are again blocked for input
|
|
|
- for x in xrange(nr_of_steps):
|
|
|
- self.execute_modelverse(user, "execute_rule", [])
|
|
|
-
|
|
|
- if not self.mvk.success:
|
|
|
- # Blocking or broken, so quit already to stop wasting CPU
|
|
|
- break
|
|
|
-
|
|
|
- # Could at least execute one instruction, so mark it as "not failed"
|
|
|
- self.all_failed = False
|
|
|
-
|
|
|
- # Check that we don't have anything to output yet, otherwise we wait
|
|
|
- if self.destination is None:
|
|
|
- # Perform output if there is anything
|
|
|
- if self.output_queue[user]:
|
|
|
- self.execute_modelverse(user, "get_output", [])
|
|
|
- if self.mvk.success:
|
|
|
- self.destination = self.output_queue[user].pop(0)
|
|
|
- self.value = self.mvk.returnvalue
|
|
|
- self.all_failed = False
|
|
|
-
|
|
|
- else:
|
|
|
- if self.count >= 2000:
|
|
|
- self.count = 0
|
|
|
- self.mvs.purge()
|
|
|
- else:
|
|
|
- self.count += 1
|
|
|
- self.mvs.garbage_collect()
|
|
|
- out = self.mvs.read_outgoing(self.root)[0]
|
|
|
- for m in out:
|
|
|
- src, user = self.mvs.read_edge(m)[0]
|
|
|
- outgoing = self.mvs.read_outgoing(m)[0]
|
|
|
- first = self.mvs.read_edge(outgoing[0])[0]
|
|
|
- dest = first[1]
|
|
|
- name = self.mvs.read_value(dest)[0]
|
|
|
- if name.startswith("__"):
|
|
|
- continue
|
|
|
- self.users.add(name)
|
|
|
- self.timeout = self.all_failed
|
|
|
- self.all_failed = True
|
|
|
- </script>
|
|
|
- </onentry>
|
|
|
-
|
|
|
- <transition cond="self.destination is not None" after="self.sccd_yield()" target=".">
|
|
|
- <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.destination">
|
|
|
- <parameter expr="json.dumps(self.value)"/>
|
|
|
- </raise>
|
|
|
- </transition>
|
|
|
-
|
|
|
- <transition cond="self.timeout and self.destination is None" after="self.sccd_yield() + 0.10" target="."/>
|
|
|
-
|
|
|
- <transition cond="not self.timeout and self.destination is None" after="self.sccd_yield()" target="."/>
|
|
|
- </state>
|
|
|
- </state>
|
|
|
-
|
|
|
- <state id="remove_sockets">
|
|
|
- <state id="remove_sockets">
|
|
|
- <transition event="delete_socket" target=".">
|
|
|
- <parameter name="socket"/>
|
|
|
- <script>
|
|
|
- for user in self.output_queue.keys():
|
|
|
- self.output_queue[user] = [s for s in self.output_queue[user] if s != socket]
|
|
|
- </script>
|
|
|
- </transition>
|
|
|
- </state>
|
|
|
- </state>
|
|
|
- </parallel>
|
|
|
- </scxml>
|
|
|
-</class>
|
|
|
+<class name="MvKController">
|
|
|
+ <relationships>
|
|
|
+ <association name="to_mvi" class="Server" min="1" max="1"/>
|
|
|
+ </relationships>
|
|
|
+ <constructor>
|
|
|
+ <parameter name="params"/>
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ self.mvs = ModelverseState("../bootstrap/bootstrap.m.gz")
|
|
|
+ # Enable Garbage Collection
|
|
|
+ self.mvs.GC = True
|
|
|
+ self.root = self.mvs.read_root()[0]
|
|
|
+
|
|
|
+ # Instantiate the kernel.
|
|
|
+ default_kernel_type = 'baseline-jit'
|
|
|
+ kernel_type = default_kernel_type
|
|
|
+ for parameter in params:
|
|
|
+ if parameter.startswith('--kernel='):
|
|
|
+ kernel_type = parameter[len('--kernel='):]
|
|
|
+
|
|
|
+ if kernel_type == 'legacy-interpreter':
|
|
|
+ self.mvk = LegacyModelverseKernel(self.root)
|
|
|
+ elif kernel_type == 'interpreter':
|
|
|
+ self.mvk = ModelverseKernel(self.root)
|
|
|
+ self.mvk.jit.set_jit_enabled(False)
|
|
|
+ else:
|
|
|
+ if kernel_type != default_kernel_type:
|
|
|
+ print(
|
|
|
+ "warning: unknown kernel type '%s'. Defaulting to '%s'."
|
|
|
+ % (kernel_type, default_kernel_type))
|
|
|
+ self.mvk = ModelverseKernel(self.root)
|
|
|
+
|
|
|
+ self.all_failed = False
|
|
|
+ self.timeout = False
|
|
|
+ self.init_time = time.time()
|
|
|
+
|
|
|
+ self.users = set()
|
|
|
+ self.input_queue = defaultdict(list)
|
|
|
+ self.output_queue = defaultdict(list)
|
|
|
+ self.source = None
|
|
|
+ self.port = int(sys.argv[1])
|
|
|
+ self.count = 0
|
|
|
+
|
|
|
+ self.debugged_users = set()
|
|
|
+ self.debug_info = {}
|
|
|
+ self.done_something = False
|
|
|
+
|
|
|
+ self.mvs_operations = {
|
|
|
+ "CN": self.mvs.create_node,
|
|
|
+ "CE": self.mvs.create_edge,
|
|
|
+ "CNV": self.mvs.create_nodevalue,
|
|
|
+ "CD": self.mvs.create_dict,
|
|
|
+
|
|
|
+ "RV": self.mvs.read_value,
|
|
|
+ "RO": self.mvs.read_outgoing,
|
|
|
+ "RI": self.mvs.read_incoming,
|
|
|
+ "RE": self.mvs.read_edge,
|
|
|
+ "RD": self.mvs.read_dict,
|
|
|
+ "RDN": self.mvs.read_dict_node,
|
|
|
+ "RDNE": self.mvs.read_dict_node_edge,
|
|
|
+ "RDE": self.mvs.read_dict_edge,
|
|
|
+ "RRD": self.mvs.read_reverse_dict,
|
|
|
+ "RR": self.mvs.read_root,
|
|
|
+ "RDK": self.mvs.read_dict_keys,
|
|
|
+
|
|
|
+ "DE": self.mvs.delete_edge,
|
|
|
+ "DN": self.mvs.delete_node,
|
|
|
+ }
|
|
|
+
|
|
|
+ self.execute_modelverse("", "load_primitives", [])
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </constructor>
|
|
|
+
|
|
|
+ <method name="execute_modelverse">
|
|
|
+ <parameter name="username"/>
|
|
|
+ <parameter name="operation"/>
|
|
|
+ <parameter name="params"/>
|
|
|
+ <body>
|
|
|
+ <![CDATA[
|
|
|
+ reply = None
|
|
|
+ commands = []
|
|
|
+ while 1:
|
|
|
+ commands = self.mvk.execute_yields(username, operation, params, reply)
|
|
|
+ if commands is None:
|
|
|
+ break
|
|
|
+ reply = [self.mvs_operations[command[0]](*(command[1]))[0] for command in commands]
|
|
|
+ #for c, r in zip(commands, reply):
|
|
|
+ # print("%s --> %s" % (c, r))
|
|
|
+ ]]>
|
|
|
+ </body>
|
|
|
+ </method>
|
|
|
+
|
|
|
+ <scxml initial="init_server">
|
|
|
+ <state id="init_server">
|
|
|
+ <onentry>
|
|
|
+ <raise scope="cd" event="create_instance">
|
|
|
+ <parameter expr="'to_mvi'"/>
|
|
|
+ <parameter expr="'Server'"/>
|
|
|
+ <parameter expr="''"/>
|
|
|
+ <parameter expr="self.port"/>
|
|
|
+ </raise>
|
|
|
+ </onentry>
|
|
|
+ <transition event="instance_created" target="../running">
|
|
|
+ <parameter name="instancename"/>
|
|
|
+ <raise scope="cd" event="start_instance">
|
|
|
+ <parameter expr="instancename"/>
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+
|
|
|
+ <parallel id="running">
|
|
|
+ <state id="wait_for_requests">
|
|
|
+ <state id="wait">
|
|
|
+ <transition event="from_mvi" target=".">
|
|
|
+ <parameter name="source"/>
|
|
|
+ <parameter name="data"/>
|
|
|
+ <script>
|
|
|
+ # No JSON encoding necessary, as it is not complex
|
|
|
+ try:
|
|
|
+ self.done_something = False
|
|
|
+ if data["op"] == "set_input":
|
|
|
+ if "value" in data:
|
|
|
+ value = [json.loads(data["value"])]
|
|
|
+ else:
|
|
|
+ value = json.loads(data["data"])
|
|
|
+ self.input_queue[data["username"]].append((source, value))
|
|
|
+ elif data["op"] == "get_output":
|
|
|
+ self.output_queue[data["username"]].append(source)
|
|
|
+ elif data["op"] == "attach_debugger":
|
|
|
+ self.debugged_users.add(data["username"])
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ self.debug_info[data["username"]] = {'state': 'running', 'breakpoints': []}
|
|
|
+ elif data["op"] == "detach_debugger":
|
|
|
+ self.debugged_users.discard(data["username"])
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ del self.debug_info[data["username"]]
|
|
|
+ elif data["op"] == "pause":
|
|
|
+ if data["username"] in self.debugged_users:
|
|
|
+ self.debug_info[data["username"]]['state'] = 'paused'
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ elif data["op"] == "resume":
|
|
|
+ if data["username"] in self.debugged_users:
|
|
|
+ self.debug_info[data["username"]]['state'] = 'running'
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ elif data["op"] == "step_over":
|
|
|
+ pass
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ elif data["op"] == "step_into":
|
|
|
+ pass
|
|
|
+ self.done_something = True
|
|
|
+ self.source = source
|
|
|
+ else:
|
|
|
+ raise Exception("DROPPING unknown operation: " + str(data["op"]))
|
|
|
+ except ValueError:
|
|
|
+ print("Error when deserializing request: " + str(data))
|
|
|
+ raise
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <transition cond="self.done_something" target=".">
|
|
|
+ <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.source">
|
|
|
+ <parameter expr="json.dumps(True)"/>
|
|
|
+ </raise>
|
|
|
+ <script>
|
|
|
+ self.done_something = False
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+
|
|
|
+ <state id="execution">
|
|
|
+ <state id="execution">
|
|
|
+ <onentry>
|
|
|
+ <script>
|
|
|
+ self.timeout = False
|
|
|
+ self.destination = None
|
|
|
+ if self.users:
|
|
|
+ user = self.users.pop()
|
|
|
+ if not user in self.debugged_users or self.debug_info[user]['state'] == 'running':
|
|
|
+ # Check if there are values to input
|
|
|
+ if self.input_queue[user]:
|
|
|
+ source, args = self.input_queue[user].pop(0)
|
|
|
+ for args_entry in args:
|
|
|
+ self.execute_modelverse(user, "set_input", [args_entry])
|
|
|
+
|
|
|
+ self.destination = source
|
|
|
+ self.value = "OK"
|
|
|
+ self.all_failed = False
|
|
|
+
|
|
|
+ nr_of_steps = 1 if user in self.debugged_users else 100
|
|
|
+ # Now process for some steps, or until we are again blocked for input
|
|
|
+ for x in xrange(nr_of_steps):
|
|
|
+ self.execute_modelverse(user, "execute_rule", [])
|
|
|
+
|
|
|
+ if not self.mvk.success:
|
|
|
+ # Blocking or broken, so quit already to stop wasting CPU
|
|
|
+ break
|
|
|
+
|
|
|
+ # Could at least execute one instruction, so mark it as "not failed"
|
|
|
+ self.all_failed = False
|
|
|
+
|
|
|
+ # Check that we don't have anything to output yet, otherwise we wait
|
|
|
+ if self.destination is None:
|
|
|
+ # Perform output if there is anything
|
|
|
+ if self.output_queue[user]:
|
|
|
+ self.execute_modelverse(user, "get_output", [])
|
|
|
+ if self.mvk.success:
|
|
|
+ self.destination = self.output_queue[user].pop(0)
|
|
|
+ self.value = self.mvk.returnvalue
|
|
|
+ self.all_failed = False
|
|
|
+
|
|
|
+ else:
|
|
|
+ if self.count >= 2000:
|
|
|
+ self.count = 0
|
|
|
+ self.mvs.purge()
|
|
|
+ else:
|
|
|
+ self.count += 1
|
|
|
+ self.mvs.garbage_collect()
|
|
|
+ out = self.mvs.read_outgoing(self.root)[0]
|
|
|
+ for m in out:
|
|
|
+ src, user = self.mvs.read_edge(m)[0]
|
|
|
+ outgoing = self.mvs.read_outgoing(m)[0]
|
|
|
+ first = self.mvs.read_edge(outgoing[0])[0]
|
|
|
+ dest = first[1]
|
|
|
+ name = self.mvs.read_value(dest)[0]
|
|
|
+ if name.startswith("__"):
|
|
|
+ continue
|
|
|
+ self.users.add(name)
|
|
|
+ self.timeout = self.all_failed
|
|
|
+ self.all_failed = True
|
|
|
+ </script>
|
|
|
+ </onentry>
|
|
|
+
|
|
|
+ <transition cond="self.destination is not None" after="self.sccd_yield()" target=".">
|
|
|
+ <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.destination">
|
|
|
+ <parameter expr="json.dumps(self.value)"/>
|
|
|
+ </raise>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <transition cond="self.timeout and self.destination is None" after="self.sccd_yield() + 0.10" target="."/>
|
|
|
+
|
|
|
+ <transition cond="not self.timeout and self.destination is None" after="self.sccd_yield()" target="."/>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+
|
|
|
+ <state id="remove_sockets">
|
|
|
+ <state id="remove_sockets">
|
|
|
+ <transition event="delete_socket" target=".">
|
|
|
+ <parameter name="socket"/>
|
|
|
+ <script>
|
|
|
+ for user in self.output_queue.keys():
|
|
|
+ self.output_queue[user] = [s for s in self.output_queue[user] if s != socket]
|
|
|
+ </script>
|
|
|
+ </transition>
|
|
|
+ </state>
|
|
|
+ </state>
|
|
|
+ </parallel>
|
|
|
+ </scxml>
|
|
|
+</class>
|