Added caching for python eval (avoid compiling when same code called, but still execute). Cleaned up some evaluator related code.
authorEdouard Tisserant
Wed, 24 Oct 2012 11:19:11 +0200 (2012-10-24)
changeset 867 06495975e8a4
parent 866 ee6adf7586c1
child 868 7e5da4962bea
Added caching for python eval (avoid compiling when same code called, but still execute). Cleaned up some evaluator related code.
Beremiz_service.py
runtime/PLCObject.py
--- a/Beremiz_service.py	Tue Oct 23 11:34:37 2012 +0200
+++ b/Beremiz_service.py	Wed Oct 24 11:19:11 2012 +0200
@@ -434,8 +434,12 @@
 if not os.path.isdir(WorkingDir):
     os.mkdir(WorkingDir)
 
-def default_evaluator(callable, *args, **kwargs):
-    return callable(*args,**kwargs)
+def default_evaluator(tocall, *args, **kwargs):
+    try:
+        res=(tocall(*args,**kwargs), None)
+    except Exception,exp:
+        res=(None, exp)
+    return res
 
 class Server():
     def __init__(self, servicename, ip_addr, port, workdir, argv, autostart=False, statuschange=None, evaluator=default_evaluator, website=None):
@@ -681,29 +685,26 @@
 if havewx:
     from threading import Semaphore
     wx_eval_lock = Semaphore(0)
-    mythread = currentThread()
+    main_thread = currentThread()
 
     def statuschange(status):
         wx.CallAfter(taskbar_instance.UpdateIcon,status)
         
-    eval_res = None
-    def wx_evaluator(callable, *args, **kwargs):
-        global eval_res
-        try:
-            eval_res=callable(*args,**kwargs)
-        except Exception,e:
-            PLCprint("#EXCEPTION : "+str(e))
-        finally:
-            wx_eval_lock.release()
-        
-    def evaluator(callable, *args, **kwargs):
-        # call directly the callable function if call from the wx mainloop (avoid dead lock) 
-        if(mythread == currentThread()):
-            callable(*args,**kwargs)
+    def wx_evaluator(obj, *args, **kwargs):
+        tocall,args,kwargs = obj.call
+        obj.res = default_evaluator(tocall, *args, **kwargs)
+        wx_eval_lock.release()
+        
+    def evaluator(tocall, *args, **kwargs):
+        global main_thread
+        if(main_thread == currentThread()):
+            # avoid dead lock if called from the wx mainloop 
+            return default_evaluator(tocall, *args, **kwargs)
         else:
-            wx.CallAfter(wx_evaluator,callable,*args,**kwargs)
+            o=type('',(object,),dict(call=(tocall, args, kwargs), res=None))
+            wx.CallAfter(wx_evaluator,o)
             wx_eval_lock.acquire()
-        return eval_res
+            return o.res
     
     pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website)
     taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx)
--- a/runtime/PLCObject.py	Tue Oct 23 11:34:37 2012 +0200
+++ b/runtime/PLCObject.py	Wed Oct 24 11:19:11 2012 +0200
@@ -222,18 +222,32 @@
         self.StartSem.release()
         self.evaluator(self.PrepareRuntimePy)
         res,cmd,blkid = "None","None",ctypes.c_void_p()
+        compile_cache={}
         while True:
             # print "_PythonIterator(", res, ")",
             cmd = self._PythonIterator(res,blkid)
+            FBID = blkid.value 
             # print " -> ", cmd, blkid
             if cmd is None:
                 break
             try :
-                self.python_threads_vars["FBID"]=blkid.value
-                res = str(self.evaluator(eval,cmd,self.python_threads_vars))
+                self.python_threads_vars["FBID"]=FBID
+                ccmd,AST =compile_cache.get(FBID, (None,None))
+                if ccmd is None or ccmd!=cmd:
+                    AST = compile(cmd, '<plc>', 'eval')
+                    compile_cache[FBID]=(cmd,AST)
+                result,exp = self.evaluator(eval,cmd,self.python_threads_vars)
+                if exp is not None: 
+                    raise(exp)
+                else:
+                    res=str(result)
+                self.python_threads_vars["FBID"]=None
             except Exception,e:
                 res = "#EXCEPTION : "+str(e)
-                PLCprint(res)
+                PLCprint(('*** Python eval EXCEPTION ***\n'+
+                          '| Function Block ID: %d\n'+
+                          '| Command : "%s"\n'+
+                          '| Exception : "%s"')%(FBID,cmd,str(e)))
         self.PLCStatus = "Stopped"
         self.StatusChange()
         self.evaluator(self.FinishRuntimePy)