Переглянути джерело

worked a bit on performance

Simon Van Mierlo 9 роки тому
батько
коміт
1a5ff12259

+ 20 - 0
examples/bouncingballs/python/runner_performance_threads.py

@@ -0,0 +1,20 @@
+'''
+Created on 27-jul.-2014
+
+@author: Simon
+'''
+
+import Tkinter as tk
+import target_py.target_performance_threads as target
+import sys
+from sccd.runtime.statecharts_core import Event
+
+if __name__ == '__main__':
+    def callback(ctrl, behind_schedule):
+        if behind_schedule > 500:
+            print len(ctrl.object_manager.instances)
+            ctrl.stop()
+            sys.exit()
+    controller = target.Controller(behind_schedule_callback=callback)
+    controller.start()
+    ui.window.mainloop()

+ 143 - 0
examples/bouncingballs/python/sccd_performance_threads.xml

@@ -0,0 +1,143 @@
+<?xml version="1.1" ?>
+<diagram author="Simon Van Mierlo+Raphael Mannadiar" name="Bouncing_Balls_Python_Version">
+    <description>
+        Tkinter frame with bouncing balls in it.
+    </description>
+    <top>
+        import random, sys
+    </top>
+    <class name="MainApp" default="true">
+        <relationships>
+            <association name="fields" class="Field" />
+        </relationships>
+        <constructor>
+            <body>
+                <![CDATA[
+                self.nr_of_fields = 0
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="running">
+            <state id="running" initial="root">
+                <parallel id="root">
+                    <state id="cd_behaviour" initial="waiting">
+                        <state id="waiting">
+                            <transition event="create_field" target="../creating">
+                                <raise scope="cd" event="create_instance">
+                                    <parameter expr='"fields"' />
+                                </raise>
+                            </transition>
+                        </state>
+                        <state id="creating">
+                            <transition event="instance_created" target="../waiting">
+                                <parameter name="association_name" type="string"/>
+                                <raise scope="cd" event="start_instance">
+                                    <parameter expr="association_name" />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="spawn_windows" initial="spawning">
+                        <state id="spawning">
+                            <transition target="." after="(1000 - self.getSimulatedTime() % 1000) / 1000.0" cond="self.nr_of_fields &lt; 10">
+                                <raise event="create_field" />
+                            </transition>
+                        </state>
+                    </state>
+                </parallel>
+                <state id="stopped" />
+            </state>
+        </scxml>
+    </class>
+
+    <class name="Field">
+        <relationships>
+            <association name="balls" class="Ball" />
+            <association name="parent" class="MainApp" min="1" max="1" />
+        </relationships>
+        <scxml initial="root">
+            <state id="root" initial="running">
+                <parallel id="running">
+                    <state id="main_behaviour" initial="running">
+                        <state id="running">
+                            <transition event="spawn_ball" target="../creating">
+                                <parameter name="x" />
+                                <parameter name="y" />
+                                <raise scope="cd" event="create_instance">
+                                    <parameter expr='"balls"' />
+                                    <parameter expr='"Ball"' />
+                                    <parameter expr="x" />
+                                    <parameter expr="y" />
+                                </raise>
+                            </transition>
+                        </state>
+                        <state id="creating">
+                            <transition event="instance_created" target="../running">
+                                <parameter name="association_name" type="string"/>
+                                <raise scope="cd" event="start_instance">
+                                    <parameter expr="association_name" />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                    <state id="spawn_balls" initial="spawning">
+                        <state id="spawning">
+                            <transition target="." after="(50 - self.getSimulatedTime() % 50) / 1000.0">
+                                <raise event="spawn_ball">
+                                    <parameter expr="150" />
+                                    <parameter expr="150" />
+                                </raise>
+                            </transition>
+                        </state>
+                    </state>
+                </parallel>
+                <state id="deleting">
+                    <transition target="../deleted">
+                        <raise event="delete_field" scope="narrow" target="'parent'">
+                            <parameter expr='self.association_name' />
+                        </raise>
+                    </transition>
+                </state>
+                <state id="deleted" />
+            </state>
+        </scxml>
+    </class>
+    
+    <class name="Ball">
+        <relationships>
+            <association name="parent" class="Field" min="1" max="1" />
+        </relationships>
+        <constructor>
+            <parameter name="x" />
+            <parameter name="y" />
+            <body>
+                <![CDATA[
+                self.r = 20.0;
+                self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
+                self.mouse_pos = {};
+                self.smooth = 0.4; # value between 0 and 1
+                self.pos = {'x': x, 'y': y}
+                ]]>
+            </body>
+        </constructor>
+        <scxml initial="main_behaviour">
+            <state id="main_behaviour" initial="bouncing">
+                <state id="bouncing">
+                    <transition after="(1000 - self.getSimulatedTime() % 1000) / 1000.0" target=".">
+                        <script>
+                            <![CDATA[
+                            self.pos
+                            if self.pos['x'] - self.r <= 0 or self.pos['x'] + self.r >= 800 :
+                                self.vel['x'] = -self.vel['x'];
+                            if self.pos['y'] - self.r <= 0 or self.pos['y'] + self.r >= 600 :
+                                self.vel['y'] = -self.vel['y'];
+                            self.pos['x'] += self.vel['x']
+                            self.pos['y'] += self.vel['y']
+                            ]]>                            
+                        </script>
+                    </transition>
+                </state>
+            </state>
+        </scxml>
+    </class>
+</diagram>

+ 2 - 5
examples/bouncingballs/python/target_py/target_performance.py

@@ -744,11 +744,8 @@ class Ball(RuntimeClassBase):
     
     def initializeStatechart(self):
         # enter default state
-        states = self.states["/main_behaviour"].getEffectiveTargetStates()
-        self.updateConfiguration(states)
-        for state in states:
-            if state.enter:
-                state.enter()
+        self.default_targets = self.states["/main_behaviour"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
 
 class ObjectManager(ObjectManagerBase):
     def __init__(self, controller):

+ 361 - 0
examples/bouncingballs/python/target_py/target_performance_threads.py

@@ -0,0 +1,361 @@
+"""
+Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
+
+Date:   Mon Aug 08 14:51:59 2016
+
+Model author: Simon Van Mierlo+Raphael Mannadiar
+Model name:   Bouncing_Balls_Python_Version
+Model description:
+Tkinter frame with bouncing balls in it.
+"""
+
+from sccd.runtime.statecharts_core import *
+import random, sys
+
+# package "Bouncing_Balls_Python_Version"
+
+class MainApp(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        MainApp.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        self.nr_of_fields = 0
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /running
+        self.states["/running"] = State(1, self)
+        
+        # state /running/root
+        self.states["/running/root"] = ParallelState(2, self)
+        
+        # state /running/root/cd_behaviour
+        self.states["/running/root/cd_behaviour"] = State(3, self)
+        
+        # state /running/root/cd_behaviour/waiting
+        self.states["/running/root/cd_behaviour/waiting"] = State(4, self)
+        
+        # state /running/root/cd_behaviour/creating
+        self.states["/running/root/cd_behaviour/creating"] = State(5, self)
+        
+        # state /running/root/spawn_windows
+        self.states["/running/root/spawn_windows"] = State(6, self)
+        
+        # state /running/root/spawn_windows/spawning
+        self.states["/running/root/spawn_windows/spawning"] = State(7, self)
+        self.states["/running/root/spawn_windows/spawning"].setEnter(self._running_root_spawn_windows_spawning_enter)
+        self.states["/running/root/spawn_windows/spawning"].setExit(self._running_root_spawn_windows_spawning_exit)
+        
+        # state /running/stopped
+        self.states["/running/stopped"] = State(8, self)
+        
+        # add children
+        self.states[""].addChild(self.states["/running"])
+        self.states["/running"].addChild(self.states["/running/root"])
+        self.states["/running"].addChild(self.states["/running/stopped"])
+        self.states["/running/root"].addChild(self.states["/running/root/cd_behaviour"])
+        self.states["/running/root"].addChild(self.states["/running/root/spawn_windows"])
+        self.states["/running/root/cd_behaviour"].addChild(self.states["/running/root/cd_behaviour/waiting"])
+        self.states["/running/root/cd_behaviour"].addChild(self.states["/running/root/cd_behaviour/creating"])
+        self.states["/running/root/spawn_windows"].addChild(self.states["/running/root/spawn_windows/spawning"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/running"]
+        self.states["/running"].default_state = self.states["/running/root"]
+        self.states["/running/root/cd_behaviour"].default_state = self.states["/running/root/cd_behaviour/waiting"]
+        self.states["/running/root/spawn_windows"].default_state = self.states["/running/root/spawn_windows/spawning"]
+        
+        # transition /running/root/cd_behaviour/waiting
+        _running_root_cd_behaviour_waiting_0 = Transition(self, self.states["/running/root/cd_behaviour/waiting"], [self.states["/running/root/cd_behaviour/creating"]])
+        _running_root_cd_behaviour_waiting_0.setAction(self._running_root_cd_behaviour_waiting_0_exec)
+        _running_root_cd_behaviour_waiting_0.setTrigger(Event("create_field", None))
+        self.states["/running/root/cd_behaviour/waiting"].addTransition(_running_root_cd_behaviour_waiting_0)
+        
+        # transition /running/root/cd_behaviour/creating
+        _running_root_cd_behaviour_creating_0 = Transition(self, self.states["/running/root/cd_behaviour/creating"], [self.states["/running/root/cd_behaviour/waiting"]])
+        _running_root_cd_behaviour_creating_0.setAction(self._running_root_cd_behaviour_creating_0_exec)
+        _running_root_cd_behaviour_creating_0.setTrigger(Event("instance_created", None))
+        self.states["/running/root/cd_behaviour/creating"].addTransition(_running_root_cd_behaviour_creating_0)
+        
+        # transition /running/root/spawn_windows/spawning
+        _running_root_spawn_windows_spawning_0 = Transition(self, self.states["/running/root/spawn_windows/spawning"], [self.states["/running/root/spawn_windows/spawning"]])
+        _running_root_spawn_windows_spawning_0.setAction(self._running_root_spawn_windows_spawning_0_exec)
+        _running_root_spawn_windows_spawning_0.setTrigger(Event("_0after"))
+        _running_root_spawn_windows_spawning_0.setGuard(self._running_root_spawn_windows_spawning_0_guard)
+        self.states["/running/root/spawn_windows/spawning"].addTransition(_running_root_spawn_windows_spawning_0)
+    
+    def _running_root_spawn_windows_spawning_enter(self):
+        self.addTimer(0, (1000 - self.getSimulatedTime() % 1000) / 1000.0)
+    
+    def _running_root_spawn_windows_spawning_exit(self):
+        self.removeTimer(0)
+    
+    def _running_root_cd_behaviour_waiting_0_exec(self, parameters):
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "fields"]))
+    
+    def _running_root_cd_behaviour_creating_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _running_root_spawn_windows_spawning_0_exec(self, parameters):
+        self.raiseInternalEvent(Event("create_field", None, []))
+    
+    def _running_root_spawn_windows_spawning_0_guard(self, parameters):
+        return self.nr_of_fields < 10
+    
+    def initializeStatechart(self):
+        # enter default state
+        self.default_targets = self.states["/running"].getEffectiveTargetStates()
+        RuntimeClassBase.initializeStatechart(self)
+
+class Field(RuntimeClassBase):
+    def __init__(self, controller):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        Field.user_defined_constructor(self)
+    
+    def user_defined_constructor(self):
+        pass
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /root
+        self.states["/root"] = State(1, self)
+        
+        # state /root/running
+        self.states["/root/running"] = ParallelState(2, self)
+        
+        # state /root/running/main_behaviour
+        self.states["/root/running/main_behaviour"] = State(3, self)
+        
+        # state /root/running/main_behaviour/running
+        self.states["/root/running/main_behaviour/running"] = State(4, self)
+        
+        # state /root/running/main_behaviour/creating
+        self.states["/root/running/main_behaviour/creating"] = State(5, self)
+        
+        # state /root/running/spawn_balls
+        self.states["/root/running/spawn_balls"] = State(6, self)
+        
+        # state /root/running/spawn_balls/spawning
+        self.states["/root/running/spawn_balls/spawning"] = State(7, self)
+        self.states["/root/running/spawn_balls/spawning"].setEnter(self._root_running_spawn_balls_spawning_enter)
+        self.states["/root/running/spawn_balls/spawning"].setExit(self._root_running_spawn_balls_spawning_exit)
+        
+        # state /root/deleting
+        self.states["/root/deleting"] = State(8, self)
+        
+        # state /root/deleted
+        self.states["/root/deleted"] = State(9, self)
+        
+        # add children
+        self.states[""].addChild(self.states["/root"])
+        self.states["/root"].addChild(self.states["/root/running"])
+        self.states["/root"].addChild(self.states["/root/deleting"])
+        self.states["/root"].addChild(self.states["/root/deleted"])
+        self.states["/root/running"].addChild(self.states["/root/running/main_behaviour"])
+        self.states["/root/running"].addChild(self.states["/root/running/spawn_balls"])
+        self.states["/root/running/main_behaviour"].addChild(self.states["/root/running/main_behaviour/running"])
+        self.states["/root/running/main_behaviour"].addChild(self.states["/root/running/main_behaviour/creating"])
+        self.states["/root/running/spawn_balls"].addChild(self.states["/root/running/spawn_balls/spawning"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/root"]
+        self.states["/root"].default_state = self.states["/root/running"]
+        self.states["/root/running/main_behaviour"].default_state = self.states["/root/running/main_behaviour/running"]
+        self.states["/root/running/spawn_balls"].default_state = self.states["/root/running/spawn_balls/spawning"]
+        
+        # transition /root/running/main_behaviour/running
+        _root_running_main_behaviour_running_0 = Transition(self, self.states["/root/running/main_behaviour/running"], [self.states["/root/running/main_behaviour/creating"]])
+        _root_running_main_behaviour_running_0.setAction(self._root_running_main_behaviour_running_0_exec)
+        _root_running_main_behaviour_running_0.setTrigger(Event("spawn_ball", None))
+        self.states["/root/running/main_behaviour/running"].addTransition(_root_running_main_behaviour_running_0)
+        
+        # transition /root/running/main_behaviour/creating
+        _root_running_main_behaviour_creating_0 = Transition(self, self.states["/root/running/main_behaviour/creating"], [self.states["/root/running/main_behaviour/running"]])
+        _root_running_main_behaviour_creating_0.setAction(self._root_running_main_behaviour_creating_0_exec)
+        _root_running_main_behaviour_creating_0.setTrigger(Event("instance_created", None))
+        self.states["/root/running/main_behaviour/creating"].addTransition(_root_running_main_behaviour_creating_0)
+        
+        # transition /root/running/spawn_balls/spawning
+        _root_running_spawn_balls_spawning_0 = Transition(self, self.states["/root/running/spawn_balls/spawning"], [self.states["/root/running/spawn_balls/spawning"]])
+        _root_running_spawn_balls_spawning_0.setAction(self._root_running_spawn_balls_spawning_0_exec)
+        _root_running_spawn_balls_spawning_0.setTrigger(Event("_0after"))
+        self.states["/root/running/spawn_balls/spawning"].addTransition(_root_running_spawn_balls_spawning_0)
+        
+        # transition /root/deleting
+        _root_deleting_0 = Transition(self, self.states["/root/deleting"], [self.states["/root/deleted"]])
+        _root_deleting_0.setAction(self._root_deleting_0_exec)
+        _root_deleting_0.setTrigger(None)
+        self.states["/root/deleting"].addTransition(_root_deleting_0)
+    
+    def _root_running_spawn_balls_spawning_enter(self):
+        self.addTimer(0, (50 - self.getSimulatedTime() % 50) / 1000.0)
+    
+    def _root_running_spawn_balls_spawning_exit(self):
+        self.removeTimer(0)
+    
+    def _root_running_main_behaviour_running_0_exec(self, parameters):
+        x = parameters[0]
+        y = parameters[1]
+        self.big_step.outputEventOM(Event("create_instance", None, [self, "balls", "Ball", x, y]))
+    
+    def _root_running_main_behaviour_creating_0_exec(self, parameters):
+        association_name = parameters[0]
+        self.big_step.outputEventOM(Event("start_instance", None, [self, association_name]))
+    
+    def _root_running_spawn_balls_spawning_0_exec(self, parameters):
+        self.raiseInternalEvent(Event("spawn_ball", None, [150, 150]))
+    
+    def _root_deleting_0_exec(self, parameters):
+        self.big_step.outputEventOM(Event("narrow_cast", None, [self, 'parent', Event("delete_field", None, [self.association_name])]))
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/root"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+class Ball(RuntimeClassBase):
+    def __init__(self, controller, x, y):
+        RuntimeClassBase.__init__(self, controller)
+        
+        self.semantics.big_step_maximality = StatechartSemantics.TakeMany
+        self.semantics.internal_event_lifeline = StatechartSemantics.Queue
+        self.semantics.input_event_lifeline = StatechartSemantics.FirstComboStep
+        self.semantics.priority = StatechartSemantics.SourceParent
+        self.semantics.concurrency = StatechartSemantics.Single
+        
+        # build Statechart structure
+        self.build_statechart_structure()
+        
+        # call user defined constructor
+        Ball.user_defined_constructor(self, x, y)
+    
+    def user_defined_constructor(self, x, y):
+        self.r = 20.0;
+        self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
+        self.mouse_pos = {};
+        self.smooth = 0.4; # value between 0 and 1
+        self.pos = {'x': x, 'y': y}
+    
+    def user_defined_destructor(self):
+        pass
+    
+    
+    # builds Statechart structure
+    def build_statechart_structure(self):
+        
+        # state <root>
+        self.states[""] = State(0, self)
+        
+        # state /main_behaviour
+        self.states["/main_behaviour"] = State(1, self)
+        
+        # state /main_behaviour/bouncing
+        self.states["/main_behaviour/bouncing"] = State(2, self)
+        self.states["/main_behaviour/bouncing"].setEnter(self._main_behaviour_bouncing_enter)
+        self.states["/main_behaviour/bouncing"].setExit(self._main_behaviour_bouncing_exit)
+        
+        # add children
+        self.states[""].addChild(self.states["/main_behaviour"])
+        self.states["/main_behaviour"].addChild(self.states["/main_behaviour/bouncing"])
+        self.states[""].fixTree()
+        self.states[""].default_state = self.states["/main_behaviour"]
+        self.states["/main_behaviour"].default_state = self.states["/main_behaviour/bouncing"]
+        
+        # transition /main_behaviour/bouncing
+        _main_behaviour_bouncing_0 = Transition(self, self.states["/main_behaviour/bouncing"], [self.states["/main_behaviour/bouncing"]])
+        _main_behaviour_bouncing_0.setAction(self._main_behaviour_bouncing_0_exec)
+        _main_behaviour_bouncing_0.setTrigger(Event("_0after"))
+        self.states["/main_behaviour/bouncing"].addTransition(_main_behaviour_bouncing_0)
+    
+    def _main_behaviour_bouncing_enter(self):
+        self.addTimer(0, (1000 - self.getSimulatedTime() % 1000) / 1000.0)
+    
+    def _main_behaviour_bouncing_exit(self):
+        self.removeTimer(0)
+    
+    def _main_behaviour_bouncing_0_exec(self, parameters):
+        self.pos
+        if self.pos['x'] - self.r <= 0 or self.pos['x'] + self.r >= 800 :
+            self.vel['x'] = -self.vel['x'];
+        if self.pos['y'] - self.r <= 0 or self.pos['y'] + self.r >= 600 :
+            self.vel['y'] = -self.vel['y'];
+        self.pos['x'] += self.vel['x']
+        self.pos['y'] += self.vel['y']
+    
+    def initializeStatechart(self):
+        # enter default state
+        states = self.states["/main_behaviour"].getEffectiveTargetStates()
+        self.updateConfiguration(states)
+        for state in states:
+            if state.enter:
+                state.enter()
+
+class ObjectManager(ObjectManagerBase):
+    def __init__(self, controller):
+        ObjectManagerBase.__init__(self, controller)
+    
+    def instantiate(self, class_name, construct_params):
+        if class_name == "MainApp":
+            instance = MainApp(self.controller)
+            instance.associations = {}
+            instance.associations["fields"] = Association("Field", 0, -1)
+        elif class_name == "Field":
+            instance = Field(self.controller)
+            instance.associations = {}
+            instance.associations["balls"] = Association("Ball", 0, -1)
+            instance.associations["parent"] = Association("MainApp", 1, 1)
+        elif class_name == "Ball":
+            instance = Ball(self.controller, construct_params[0], construct_params[1])
+            instance.associations = {}
+            instance.associations["parent"] = Association("Field", 1, 1)
+        else:
+            raise Exception("Cannot instantiate class " + class_name)
+        return instance
+
+class Controller(ThreadsControllerBase):
+    def __init__(self, keep_running = None, behind_schedule_callback = None):
+        if keep_running == None: keep_running = True
+        if behind_schedule_callback == None: behind_schedule_callback = None
+        ThreadsControllerBase.__init__(self, ObjectManager(self), keep_running, behind_schedule_callback)
+        self.object_manager.createInstance("MainApp", [])

+ 2 - 0
src/python_sccd/python_sccd_compiler/generic_generator.py

@@ -121,6 +121,7 @@ class GenericGenerator(Visitor):
             self.writer.addFormalParameter("behind_schedule_callback", GLC.NoneExpression())
         elif self.platform == Platforms.Threads:
             self.writer.addFormalParameter("keep_running", GLC.TrueExpression())
+            self.writer.addFormalParameter("behind_schedule_callback", GLC.NoneExpression())
         self.writer.beginMethodBody()
         self.writer.beginSuperClassConstructorCall(controller_sub_class)
         self.writer.addActualParameter(GLC.NewExpression("ObjectManager", [GLC.SelfExpression()]))
@@ -130,6 +131,7 @@ class GenericGenerator(Visitor):
             self.writer.addActualParameter("behind_schedule_callback")
         elif self.platform == Platforms.Threads:
             self.writer.addActualParameter("keep_running")
+            self.writer.addActualParameter("behind_schedule_callback")
         self.writer.endSuperClassConstructorCall()
         for i in class_diagram.inports:
             self.writer.add(GLC.FunctionCall(GLC.SelfProperty("addInputPort"), [GLC.String(i)]))

+ 32 - 29
src/python_sccd/python_sccd_runtime/statecharts_core.py

@@ -3,6 +3,7 @@ import re
 import threading
 import traceback
 import math
+import cPickle
 from infinity import INFINITY
 from Queue import Queue, Empty
 
@@ -97,8 +98,9 @@ class ObjectManagerBase(object):
     
     def stepAll(self):
         self.step()
+        simulated_time = self.controller.simulated_time
         for i in self.instances:
-            if i.active and (i.getEarliestEventTime() <= self.controller.simulated_time or i.eventlessTransitions()):
+            if i.active and (i.earliest_event_time <= simulated_time or i.eventless_states):
                 i.step()
 
     def step(self):
@@ -508,11 +510,14 @@ class EventLoopControllerBase(ControllerBase):
                 self.simulated_time = earliest_event_time
         
 class ThreadsControllerBase(ControllerBase):
-    def __init__(self, object_manager, keep_running):
+    def __init__(self, object_manager, keep_running, behind_schedule_callback = None):
         ControllerBase.__init__(self, object_manager)
         self.keep_running = keep_running
+        self.behind_schedule_callback = behind_schedule_callback
         self.input_condition = threading.Condition()
         self.stop_thread = False
+        self.last_print_time = 0
+        self.behind = False
 
     def addInput(self, input_event, time_offset = 0):
         with self.input_condition:
@@ -543,18 +548,30 @@ class ThreadsControllerBase(ControllerBase):
             earliest_event_time = self.getEarliestEventTime()
             if earliest_event_time == INFINITY and not self.keep_running:
                 return
-            with self.input_condition:
-                self.input_condition.wait((earliest_event_time - time()) / 1000.0)
+            now = time()
+            if earliest_event_time - now > 0:
+                if self.behind:                
+                    print '\r' + ' ' * 80,
+                    self.behind = False
+                with self.input_condition:
+                    self.input_condition.wait((earliest_event_time - now) / 1000.0)
+            else:
+                if now - self.last_print_time >= 1000:
+                    if self.behind_schedule_callback:
+                        self.behind_schedule_callback(self, now - earliest_event_time)
+                    print '\rrunning %ims behind schedule' % (now - earliest_event_time),
+                    self.last_print_time = now
+                    self.behind = True
             earliest_event_time = self.getEarliestEventTime()
             if earliest_event_time == INFINITY:
                 if self.keep_running:
                     with self.input_condition:
                         self.input_condition.wait()
+                        earliest_event_time = self.getEarliestEventTime()
                 else:
                     self.stop_thread = True
             if self.stop_thread:
                 break
-            earliest_event_time = self.getEarliestEventTime()
             self.simulated_time = earliest_event_time
 
 class StatechartSemantics:
@@ -633,18 +650,6 @@ class State:
         
     def setExit(self, exit):
         self.exit = exit
-    
-    def __eq__(self, other):
-        if isinstance(other, self.__class__):
-            return self.state_id == other.state_id
-        else:
-            return False
-
-    def __ne__(self, other):
-        return not self.__eq__(other)
-    
-    def __hash__(self):
-        return self.state_id
         
     def __repr__(self):
         return "State(%i)" % self.state_id
@@ -706,7 +711,7 @@ class Transition:
             return (self.guard is None) or self.guard([])
         else:
             for event in events:
-                if ((self.trigger is None) or (self.trigger.name == event.name and (not self.trigger.port or self.trigger.port == event.port))) and ((self.guard is None) or self.guard(event.parameters)):
+                if (self.trigger.name == event.name and (not self.trigger.port or self.trigger.port == event.port)) and ((self.guard is None) or self.guard(event.parameters)):
                     self.enabled_event = event
                     return True
     
@@ -722,6 +727,7 @@ class Transition:
                     f = lambda s0: not s0.descendants and s0 in s.descendants
                 self.obj.history_values[h.state_id] = filter(f, self.obj.configuration)
         for s in exit_set:
+            self.obj.eventless_states -= s.has_eventless_transitions
             # execute exit action(s)
             if s.exit:
                 s.exit()
@@ -738,6 +744,7 @@ class Transition:
         # enter states...
         enter_set = self.__enterSet(targets)
         for s in enter_set:
+            self.obj.eventless_states += s.has_eventless_transitions
             self.obj.configuration.append(s)
             # execute enter action(s)
             if s.enter:
@@ -807,6 +814,7 @@ class RuntimeClassBase(object):
         self.inports = {}
         self.timers = {}
         self.states = {}
+        self.eventless_states = 0
 
         self.semantics = StatechartSemantics()
 
@@ -830,9 +838,6 @@ class RuntimeClassBase(object):
         
     def getSimulatedTime(self):
         return self.controller.simulated_time
-        
-    def eventlessTransitions(self):
-        return sum(map(lambda x: x.has_eventless_transitions, self.configuration))
     
     def updateConfiguration(self, states):
         self.configuration.extend(states)
@@ -859,9 +864,6 @@ class RuntimeClassBase(object):
             event_list = [event_list]
         for e in event_list:
             self.events.add((event_time, e))
-        
-    def getEarliestEventTime(self):
-        return self.earliest_event_time
 
     def processBigStepOutput(self):
         for e in self.big_step.output_events_port:
@@ -895,12 +897,10 @@ class RuntimeClassBase(object):
     def inState(self, state_strings):
         state_ids = [self.states[state_string].state_id for state_string in state_strings]
         for state_id in state_ids:
-            found = False
             for s in self.configuration:
                 if s.state_id == state_id:
-                    found = True
                     break
-            if not found:
+            else:
                 return False
         return True
 
@@ -983,9 +983,12 @@ class RuntimeClassBase(object):
         elif self.semantics.internal_event_lifeline == StatechartSemantics.Queue:
             self.events.add((time(), event))
 
-    @abc.abstractmethod
     def initializeStatechart(self):
-        pass
+        self.updateConfiguration(self.default_targets)
+        for state in self.default_targets:
+            self.eventless_states += state.has_eventless_transitions
+            if state.enter:
+                state.enter()
         
 
 class BigStepState(object):