Added support for optimizing debug, preventing to filling buffers with only the last value for debug data consumers that only show the current state
authorLaurent Bessard
Mon, 14 Oct 2013 12:28:44 +0200
changeset 1365 debc97102b23
parent 1364 e9e17d3b2849
child 1366 3756ae754713
Added support for optimizing debug, preventing to filling buffers with only the last value for debug data consumers that only show the current state
ProjectController.py
controls/DebugVariablePanel/DebugVariableItem.py
controls/DebugVariablePanel/DebugVariablePanel.py
controls/DebugVariablePanel/DebugVariableViewer.py
editors/DebugViewer.py
graphics/DebugDataConsumer.py
--- a/ProjectController.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/ProjectController.py	Mon Oct 14 12:28:44 2013 +0200
@@ -1202,7 +1202,7 @@
             self.IECdebug_lock.acquire()
             IECPathsToPop = []
             for IECPath,data_tuple in self.IECdebug_datas.iteritems():
-                WeakCallableDict, data_log, status, fvalue = data_tuple
+                WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
                 if len(WeakCallableDict) == 0:
                     # Callable Dict is empty.
                     # This variable is not needed anymore!
@@ -1268,10 +1268,13 @@
                     WeakKeyDictionary(), # Callables
                     [],                  # Data storage [(tick, data),...]
                     "Registered",        # Variable status
-                    None]                # Forced value
+                    None,
+                    buffer_list]                # Forced value
             self.IECdebug_datas[IECPath] = IECdebug_data
-        
-        IECdebug_data[0][callableobj]=(args, kwargs)
+        else:
+            IECdebug_data[4] |= buffer_list
+        
+        IECdebug_data[0][callableobj]=(buffer_list, args, kwargs)
 
         self.IECdebug_lock.release()
         
@@ -1286,6 +1289,12 @@
             IECdebug_data[0].pop(callableobj,None)
             if len(IECdebug_data[0]) == 0:
                 self.IECdebug_datas.pop(IECPath)
+            else:
+                IECdebug_data[4] = reduce(
+                    lambda x, y: x|y,
+                    [buffer_list for buffer_list,args,kwargs 
+                     in IECdebug_data[0].itervalues()],
+                    False)
         self.IECdebug_lock.release()
 
         self.ReArmDebugRegisterTimer()
@@ -1330,16 +1339,15 @@
     def CallWeakcallables(self, IECPath, function_name, *cargs):
         data_tuple = self.IECdebug_datas.get(IECPath, None)
         if data_tuple is not None:
-            WeakCallableDict, data_log, status, fvalue = data_tuple
+            WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
             #data_log.append((debug_tick, value))
-            for weakcallable,(args,kwargs) in WeakCallableDict.iteritems():
+            for weakcallable,(buffer_list,args,kwargs) in WeakCallableDict.iteritems():
                 function = getattr(weakcallable, function_name, None)
                 if function is not None:
-                    if status == "Forced" and cargs[1] == fvalue:
-                        function(*(cargs + (True,) + args), **kwargs)
+                    if buffer_list:
+                        function(*(cargs + args), **kwargs)
                     else:
-                        function(*(cargs + args), **kwargs)
-                # This will block thread if more than one call is waiting
+                        function(*(tuple([lst[-1] for lst in cargs]) + args), **kwargs)
 
     def GetTicktime(self):
         return self._Ticktime
@@ -1365,13 +1373,19 @@
             #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
             if plc_status == "Started":
                 self.IECdebug_lock.acquire()
-                if len(debug_vars) == len(self.DebugValuesBuffers):
+                if (len(debug_vars) == len(self.DebugValuesBuffers) and
+                    len(debug_vars) == len(self.TracedIECPath)):
                     if debug_getvar_retry > DEBUG_RETRIES_WARN:
                         self.logger.write(_("... debugger recovered\n"))
                     debug_getvar_retry = 0
-                    for values_buffer, value in zip(self.DebugValuesBuffers, debug_vars):
-                        if value is not None:
-                            values_buffer.append(value)
+                    for IECPath, values_buffer, value in zip(self.TracedIECPath, self.DebugValuesBuffers, debug_vars):
+                        IECdebug_data = self.IECdebug_datas.get(IECPath, None)
+                        if IECdebug_data is not None and value is not None:
+                            forced = IECdebug_data[2:4] == ["Forced", value]
+                            if not IECdebug_data[4] and len(values_buffer) > 0:
+                                values_buffer[-1] = (value, forced)
+                            else:
+                                values_buffer.append((value, forced))
                     self.DebugTicks.append(debug_tick)
                 self.IECdebug_lock.release()
                 if debug_getvar_retry == DEBUG_RETRIES_WARN:
--- a/controls/DebugVariablePanel/DebugVariableItem.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableItem.py	Mon Oct 14 12:28:44 2013 +0200
@@ -232,14 +232,14 @@
         return (self.Parent.IsNumType(self.VariableType) or 
                 self.VariableType in ["STRING", "WSTRING"])
     
-    def NewValues(self, ticks, values, forced=False):
+    def NewValues(self, ticks, values):
         """
         Function called by debug thread when a new debug value is available
         @param tick: PLC tick when value was captured
         @param value: Value captured
         @param forced: Forced flag, True if value is forced (default: False)
         """
-        DebugDataConsumer.NewValues(self, ticks, values, forced, raw=None)
+        DebugDataConsumer.NewValues(self, ticks[-1], values[-1], raw=None)
         
         if self.Data is not None:
             
@@ -247,13 +247,12 @@
                 last_raw_data = (self.RawData[-1]
                                  if len(self.RawData) > 0 else None)
                 last_raw_data_idx = len(self.RawData) - 1
-                
-            # Translate forced flag to float for storing in Data table
-            forced_value = float(forced)
             
             data_values = []
-            for tick, value in zip(ticks, values):
-            
+            for tick, (value, forced) in zip(ticks, values):
+                # Translate forced flag to float for storing in Data table
+                forced_value = float(forced)
+                
                 # String data value is CRC
                 num_value = (binascii.crc32(value) & STRING_CRC_MASK
                              if self.VariableType in ["STRING", "WSTRING"]
--- a/controls/DebugVariablePanel/DebugVariablePanel.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariablePanel.py	Mon Oct 14 12:28:44 2013 +0200
@@ -754,7 +754,7 @@
         if idx is None:
             idx = len(self.GraphicPanels)
         item = DebugVariableItem(self, iec_path, True)
-        result = self.AddDataConsumer(iec_path.upper(), item)
+        result = self.AddDataConsumer(iec_path.upper(), item, True)
         if result is not None or force:
             
             self.Freeze()
@@ -832,7 +832,7 @@
         if source_item is None:
             item = DebugVariableItem(self, source, True)
             if item.IsNumVariable():
-                result = self.AddDataConsumer(source.upper(), item)
+                result = self.AddDataConsumer(source.upper(), item, True)
                 if result is not None or force:
                     source_item = item
         if source_item is not None and source_item.IsNumVariable():
--- a/controls/DebugVariablePanel/DebugVariableViewer.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/controls/DebugVariablePanel/DebugVariableViewer.py	Mon Oct 14 12:28:44 2013 +0200
@@ -149,7 +149,7 @@
                 self.RemoveItem(item)
             else:
                 # If it exist, resubscribe and refresh data type
-                self.ParentWindow.AddDataConsumer(iec_path.upper(), item)
+                self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
                 item.RefreshVariableType()
     
     def ResetItemsData(self):
--- a/editors/DebugViewer.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/editors/DebugViewer.py	Mon Oct 14 12:28:44 2013 +0200
@@ -106,7 +106,7 @@
             
             # Subscribe tick to new data producer
             if producer is not None:
-                producer.SubscribeDebugIECVariable("__tick__", self)
+                producer.SubscribeDebugIECVariable("__tick__", self, True)
             
             # Unsubscribe tick from old data producer
             if getattr(self, "DataProducer", None) is not None:
@@ -134,7 +134,7 @@
         # Save inhibit flag
         self.Inhibited = inhibit
     
-    def AddDataConsumer(self, iec_path, consumer):
+    def AddDataConsumer(self, iec_path, consumer, buffer_list=False):
         """
         Subscribe data consumer to DataProducer
         @param iec_path: Path in PLC of variable needed by data consumer
@@ -148,7 +148,7 @@
         
         # Subscribe data consumer to DataProducer
         result = self.DataProducer.SubscribeDebugIECVariable(
-                        iec_path, consumer)
+                        iec_path, consumer, buffer_list)
         if result is not None and consumer != self:
             
             # Store data consumer if successfully subscribed and inform
@@ -178,7 +178,7 @@
         """
         # Subscribe tick if needed
         if self.SubscribeTick and self.Debug and self.DataProducer is not None:
-            self.DataProducer.SubscribeDebugIECVariable("__tick__", self)
+            self.DataProducer.SubscribeDebugIECVariable("__tick__", self, True)
     
     def UnsubscribeAllDataConsumers(self, tick=True):
         """
--- a/graphics/DebugDataConsumer.py	Mon Oct 14 10:49:04 2013 +0200
+++ b/graphics/DebugDataConsumer.py	Mon Oct 14 12:28:44 2013 +0200
@@ -197,7 +197,7 @@
         """
         self.DataType = data_type
     
-    def NewValues(self, ticks, values, forced=False, raw="BOOL"):
+    def NewValues(self, tick, values, raw="BOOL"):
         """
         Function called by debug thread when a new debug value is available
         @param tick: PLC tick when value was captured
@@ -205,7 +205,7 @@
         @param forced: Forced flag, True if value is forced (default: False)
         @param raw: Data type of values not translated (default: 'BOOL')
         """
-        tick, value = ticks[-1], values[-1]
+        value, forced = values
         
         # Translate value to IEC literal
         if self.DataType != raw: