Added caching for python eval (avoid compiling when same code called, but still execute). Cleaned up some evaluator related code.
--- 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)