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
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)