瀏覽代碼

fire_transition: exit set generation performance improvement.

Joeri Exelmans 5 年之前
父節點
當前提交
1bb5680d0d
共有 2 個文件被更改,包括 47 次插入12 次删除
  1. 8 2
      src/sccd/statechart/dynamic/statechart_execution.py
  2. 39 10
      src/sccd/util/bitmap.py

+ 8 - 2
src/sccd/statechart/dynamic/statechart_execution.py

@@ -59,7 +59,13 @@ class StatechartExecution:
 
     # events: list SORTED by event id
     def fire_transition(self, events: List[Event], t: Transition):
-        try:            
+        try:
+            # Exit set is the intersection between self.configuration and t.gen.arena.descendants.
+
+            # The following was found to be more efficient than reverse-iterating and filtering self.configuration or t.arena.gen.descendants lists, despite the fact that Bitmap.reverse_items() isn't very efficient.
+            exit_ids = self.configuration_bitmap & t.gen.arena.gen.descendant_bitmap
+            exit_set = (self.statechart.tree.state_list[id] for id in exit_ids.reverse_items())
+
             def __enterSet(targets):
                 target = targets[0]
                 for a in reversed(target.gen.ancestors):
@@ -83,7 +89,6 @@ class StatechartExecution:
             print_debug("fire " + str(t))
 
             # exit states...
-            exit_set = (s for s in reversed(self.configuration) if s.gen.state_id_bitmap & t.gen.arena.gen.descendant_bitmap)
             for s in exit_set:
                 # remember which state(s) we were in if a history state is present
                 for h in s.gen.history:
@@ -109,6 +114,7 @@ class StatechartExecution:
             self.rhs_memory.pop_frame()
                 
             # enter states...
+            enter_set = (t.gen.arena.gen.descendants)
             for s in __enterSet(__getEffectiveTargetStates()):
                 print_debug(termcolor.colored('  ENTER %s' % s.gen.full_name, 'green'))
                 self.eventless_states += s.gen.has_eventless_transitions

+ 39 - 10
src/sccd/util/bitmap.py

@@ -1,6 +1,5 @@
 from typing import *
 from functools import reduce
-import math
 
 # Bitmap inherits 'int' and is therefore immutable.
 # Methods that return a Bitmap return a new bitmap and leave the arguments untouched.
@@ -13,11 +12,11 @@ class Bitmap(int):
   # iterable: positions of bits to set.
   @classmethod
   def from_list(cls, iterable):
-    v = reduce(lambda x,y: x|2**y, iterable, 0) # iterable
+    v = reduce(lambda x,y: x|1<<y, iterable, 0) # iterable
     return super(cls, cls).__new__(cls, v)
 
   def __repr__(self):
-    return "Bitmap("+format(self, 'b')+")"
+    return "Bitmap('"+format(self, 'b')+"')"
 
   def __str__(self):
     return self.__repr__()
@@ -31,23 +30,53 @@ class Bitmap(int):
   def __invert__(self):
     return self.__class__(super().__invert__())
 
+  def __neg__(self):
+    return self.__class__(super().__neg__())
+
   def has(self, pos):
-    return self & 2**pos
+    return self & 1 << pos
 
   def has_all(self, bitmap):
     return (self | bitmap) == self
 
-  # pos of first set bit
-  def first_bit_pos(self):
-    return math.floor(math.log2(x & -x))
+  def lowest_bit(self) -> int:
+    low = self & -self # only the lowest bit set
+    pos = -1
+    while low:
+      low >>= 1
+      pos += 1
+    return pos
+
+  def highest_bit(self) -> int:
+    pos = -1
+    while self:
+      self >>= 1
+      pos += 1
+    return pos
 
+  # Takes 1 iteration over our bitmap
   def items(self) -> Iterable[int]:
     pos = 0
-    while 2**pos <= self:
-      if self & 2**pos:
+    while self > 0:
+      if (self >> 1) << 1 != self:
         yield pos
       pos += 1
+      self >>= 1
+
+  # Takes 2 iterations over our bitmap, one for highest_bit,
+  # and then to find the rest of the bits.
+  def reverse_items(self) -> Iterable[int]:
+    pos = self.highest_bit()
+    if pos >= 0:
+      yield pos
+    pos -= 1
+    while pos >= 0:
+      high = 1 << pos
+      if self & high:
+        yield pos
+      self -= high # unset high bit
+      pos -= 1
 
 # Create a bitmap with a single bit set.
 def bit(pos):
-  return Bitmap(2 ** pos)
+  return Bitmap(1 << pos)