1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 # File : SALOME_PyNode.py
22 # Author : Christian CAREMOLI, EDF
35 from SALOME_ContainerHelper import ScriptExecInfo
37 MY_CONTAINER_ENTRY_IN_GLBS = "my_container"
39 MY_PERFORMANCE_LOG_ENTRY_IN_GLBS = "my_log_4_this_session"
41 class Generic(SALOME__POA.GenericObj):
42 """A Python implementation of the GenericObj CORBA IDL"""
43 def __init__(self,poa):
48 #print("Register called : %d"%self.cnt)
52 #print("UnRegister called : %d"%self.cnt)
55 oid=self.poa.servant_to_id(self)
56 self.poa.deactivate_object(oid)
59 print("WARNING SALOME::GenericObj::Destroy() function is obsolete! Use UnRegister() instead.")
63 #print("Destuctor called")
66 class PyNode_i (Engines__POA.PyNode,Generic):
67 """The implementation of the PyNode CORBA IDL"""
68 def __init__(self, nodeName,code,poa,my_container):
69 """Initialize the node : compilation in the local context"""
70 Generic.__init__(self,poa)
71 self.nodeName=nodeName
73 self.my_container=my_container._container
74 linecache.cache[nodeName]=0,None,code.split('\n'),nodeName
75 ccode=compile(code,nodeName,'exec')
77 self.context[MY_CONTAINER_ENTRY_IN_GLBS] = self.my_container
78 exec(ccode, self.context)
80 def getContainer(self):
81 return self.my_container
89 def defineNewCustomVar(self,varName,valueOfVar):
90 self.context[varName] = pickle.loads(valueOfVar)
93 def executeAnotherPieceOfCode(self,code):
94 """Called for initialization of container lodging self."""
96 ccode=compile(code,self.nodeName,'exec')
97 exec(ccode, self.context)
99 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"","PyScriptNode (%s) : code to be executed \"%s\"" %(self.nodeName,code),0))
101 def execute(self,funcName,argsin):
102 """Execute the function funcName found in local context with pickled args (argsin)"""
104 argsin,kws=pickle.loads(argsin)
105 func=self.context[funcName]
106 argsout=func(*argsin,**kws)
107 argsout=pickle.dumps(argsout,-1)
110 exc_typ,exc_val,exc_fr=sys.exc_info()
111 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
112 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyNode: %s, function: %s" % (self.nodeName,funcName),0))
114 class SenderByte_i(SALOME__POA.SenderByte,Generic):
115 def __init__(self,poa,bytesToSend):
116 Generic.__init__(self,poa)
117 self.bytesToSend = bytesToSend
120 return len(self.bytesToSend)
122 def sendPart(self,n1,n2):
123 return self.bytesToSend[n1:n2]
125 SALOME_FILE_BIG_OBJ_DIR = "SALOME_FILE_BIG_OBJ_DIR"
127 SALOME_BIG_OBJ_ON_DISK_THRES_VAR = "SALOME_BIG_OBJ_ON_DISK_THRES"
130 SALOME_BIG_OBJ_ON_DISK_THRES_DFT = 50000000
132 DicoForProxyFile = { }
134 def GetSizeOfBufferedReader(f):
136 This method returns in bytes size of a file openned.
140 f (io.IOBase): buffered reader returned by open
148 f.seek(0,io.SEEK_END)
150 f.seek(pos,io.SEEK_SET)
153 def GetObjectFromFile(fname, visitor = None):
154 with open(fname,"rb") as f:
156 visitor.setHDDMem( GetSizeOfBufferedReader(f) )
157 visitor.setFileName( fname )
161 def DumpInFile(obj,fname):
162 with open(fname,"wb") as f:
165 def IncrRefInFile(fname):
166 if fname in DicoForProxyFile:
167 DicoForProxyFile[fname] += 1
169 DicoForProxyFile[fname] = 2
172 def DecrRefInFile(fname):
173 if fname not in DicoForProxyFile:
176 cnt = DicoForProxyFile[fname]
177 DicoForProxyFile[fname] -= 1
179 del DicoForProxyFile[fname]
181 if os.path.exists(fname):
185 def GetBigObjectOnDiskThreshold():
187 if SALOME_BIG_OBJ_ON_DISK_THRES_VAR in os.environ:
188 return int( os.environ[SALOME_BIG_OBJ_ON_DISK_THRES_VAR] )
190 return SALOME_BIG_OBJ_ON_DISK_THRES_DFT
192 def ActivateProxyMecanismOrNot( sizeInByte ):
193 thres = GetBigObjectOnDiskThreshold()
197 return sizeInByte > thres
199 def GetBigObjectDirectory():
201 if SALOME_FILE_BIG_OBJ_DIR not in os.environ:
202 raise RuntimeError("An object of size higher than limit detected and no directory specified to dump it in file !")
203 return os.path.expanduser( os.path.expandvars( os.environ[SALOME_FILE_BIG_OBJ_DIR] ) )
205 def GetBigObjectFileName():
207 Return a filename in the most secure manner (see tempfile documentation)
210 with tempfile.NamedTemporaryFile(dir=GetBigObjectDirectory(),prefix="mem_",suffix=".pckl") as f:
214 class BigObjectOnDiskBase:
215 def __init__(self, fileName, objSerialized):
217 :param fileName: the file used to dump into.
218 :param objSerialized: the object in pickeled form
219 :type objSerialized: bytes
221 self._filename = fileName
222 # attribute _destroy is here to tell client side or server side
223 # only client side can be with _destroy set to True. server side due to risk of concurrency
224 # so pickled form of self must be done with this attribute set to False.
225 self._destroy = False
226 self.__dumpIntoFile(objSerialized)
228 def getDestroyStatus(self):
233 IncrRefInFile( self._filename )
235 # should never happen !
236 RuntimeError("Invalid call to incrRef !")
240 DecrRefInFile( self._filename )
242 # should never happen !
243 RuntimeError("Invalid call to decrRef !")
245 def unlinkOnDestructor(self):
248 def doNotTouchFile(self):
250 Method called slave side. The life cycle management of file is client side not slave side.
252 self._destroy = False
256 DecrRefInFile( self._filename )
258 def getFileName(self):
259 return self._filename
261 def __dumpIntoFile(self, objSerialized):
262 DumpInFile( objSerialized, self._filename )
264 def get(self, visitor = None):
265 obj = GetObjectFromFile( self._filename, visitor )
269 return float( self.get() )
272 return int( self.get() )
276 if isinstance(obj,str):
279 raise RuntimeError("Not a string")
281 class BigObjectOnDisk(BigObjectOnDiskBase):
282 def __init__(self, fileName, objSerialized):
283 BigObjectOnDiskBase.__init__(self, fileName, objSerialized)
285 class BigObjectOnDiskListElement(BigObjectOnDiskBase):
286 def __init__(self, pos, length, fileName):
287 self._filename = fileName
288 self._destroy = False
290 self._length = length
292 def get(self, visitor = None):
293 fullObj = BigObjectOnDiskBase.get(self, visitor)
294 return fullObj[ self._pos ]
296 def __getitem__(self, i):
300 return len(self.get())
302 class BigObjectOnDiskSequence(BigObjectOnDiskBase):
303 def __init__(self, length, fileName, objSerialized):
304 BigObjectOnDiskBase.__init__(self, fileName, objSerialized)
305 self._length = length
307 def __getitem__(self, i):
308 return BigObjectOnDiskListElement(i, self._length, self.getFileName())
313 class BigObjectOnDiskList(BigObjectOnDiskSequence):
314 def __init__(self, length, fileName, objSerialized):
315 BigObjectOnDiskSequence.__init__(self, length, fileName, objSerialized)
317 class BigObjectOnDiskTuple(BigObjectOnDiskSequence):
318 def __init__(self, length, fileName, objSerialized):
319 BigObjectOnDiskSequence.__init__(self, length, fileName, objSerialized)
321 def ProxyfyPickeled( obj, pickleObjInit = None, visitor = None ):
323 This method return a proxy instance of pickled form of object given in input.
327 obj (pickelable type) : object to be proxified
328 pickleObjInit (bytes) : Optionnal. Original pickeled form of object to be proxyfied if already computed. If not this method generate it
332 BigObjectOnDiskBase: proxy instance
334 pickleObj = pickleObjInit
335 if pickleObj is None:
336 pickleObj = pickle.dumps( obj , pickle.HIGHEST_PROTOCOL )
337 fileName = GetBigObjectFileName()
339 visitor.setHDDMem( len(pickleObj) )
340 visitor.setFileName(fileName)
341 if isinstance( obj, list):
342 proxyObj = BigObjectOnDiskList( len(obj), fileName, pickleObj )
343 elif isinstance( obj, tuple):
344 proxyObj = BigObjectOnDiskTuple( len(obj), fileName , pickleObj )
346 proxyObj = BigObjectOnDisk( fileName , pickleObj )
349 def SpoolPickleObject( obj, visitor = None ):
351 with InOutputObjVisitorCM(visitor) as v:
352 pickleObjInit = pickle.dumps( obj , pickle.HIGHEST_PROTOCOL )
353 if not ActivateProxyMecanismOrNot( len(pickleObjInit) ):
356 proxyObj = ProxyfyPickeled( obj, pickleObjInit, v.visitor() )
357 pickleProxy = pickle.dumps( proxyObj , pickle.HIGHEST_PROTOCOL )
360 from SALOME_ContainerHelper import InOutputObjVisitorCM, InOutputObjVisitor
362 def UnProxyObjectSimple( obj, visitor = None ):
364 Method to be called in Remote mode. Alterate the obj _status attribute.
365 Because the slave process does not participate in the reference counting
369 visitor (InOutputObjVisitor): A visitor to keep track of amount of memory on chip and those on HDD
372 with InOutputObjVisitorCM(visitor) as v:
373 logging.debug( "UnProxyObjectSimple {}".format(type(obj)) )
374 if isinstance(obj,BigObjectOnDiskBase):
377 elif isinstance( obj, list):
380 retObj.append( UnProxyObjectSimple(elt,v.visitor()) )
385 def UnProxyObjectSimpleLocal( obj ):
387 Method to be called in Local mode. Do not alterate the PyObj counter
389 if isinstance(obj,BigObjectOnDiskBase):
391 elif isinstance( obj, list):
394 retObj.append( UnProxyObjectSimpleLocal(elt) )
400 def __init__(self, fileName):
401 self._filename = fileName
404 return self._filename
406 class FileDeleter(FileHolder):
407 def __init__(self, fileName):
408 super().__init__( fileName )
411 if os.path.exists( self._filename ):
412 os.unlink( self._filename )
414 class MonitoringInfo:
415 def __init__(self, pyFileName, intervalInMs, outFileName, pid):
416 self._py_file_name = pyFileName
417 self._interval_in_ms = intervalInMs
418 self._out_file_name = outFileName
422 def pyFileName(self):
423 return self._py_file_name
430 def pid(self, value):
434 def outFileName(self):
435 return self._out_file_name
438 def intervalInMs(self):
439 return self._interval_in_ms
441 def FileSystemMonitoring(intervalInMs, dirNameToInspect, outFileName = None):
443 This method loops indefinitely every intervalInMs milliseconds to scan
444 number of inodes and size of content recursively included into the in input directory.
449 outFileName (str) : name of file inside the results will be written. If None a new file is generated
451 See also CPUMemoryMonitoring
455 dirNameToInspect2 = os.path.abspath( os.path.expanduser(dirNameToInspect) )
459 # outFileNameSave stores the content of outFileName during phase of dumping
460 with tempfile.NamedTemporaryFile(prefix="fs_monitor_",suffix=".txt") as f:
461 outFileNameSave = f.name
462 with tempfile.NamedTemporaryFile(prefix="fs_monitor_",suffix=".py") as f:
464 tempOutFile = outFileName
465 if tempOutFile is None:
466 tempOutFile = "{}.txt".format( os.path.splitext( tempPyFile )[0] )
467 with open(tempPyFile,"w") as f:
469 import subprocess as sp
474 with open("{tempOutFile}","a") as f:
475 f.write( "{{}}\\n".format( "{dirNameToInspect2}" ) )
476 f.write( "{{}}\\n".format( "{intervalInMs}" ) )
478 nbinodes = sp.check_output("{{}} | wc -l".format( " ".join(["find","{dirNameToInspect2}"]), ), shell = True).decode().strip()
479 szOfDirStr = re.split("[\s]+",sp.check_output(["du","-sh","{dirNameToInspect2}"]).decode())[0]
480 f.write( "{{}}\\n".format( str( datetime.datetime.now().timestamp() ) ) )
481 f.write( "{{}}\\n".format( str( nbinodes ) ) )
482 f.write( "{{}}\\n".format( str( szOfDirStr ) ) )
484 time.sleep( {intervalInMs} / 1000.0 )
485 """.format( **locals()))
486 logging.debug( "File for FS monitoring dump file : {}".format(tempPyFile) )
487 pyFileName = FileDeleter( tempPyFile )
488 if outFileName is None:
489 outFileName = FileDeleter( tempOutFile )
491 outFileName = FileHolder(outFileName)
492 return MonitoringInfo(pyFileName, intervalInMs, outFileName, None)
494 def CPUMemoryMonitoring( intervalInMs, outFileName = None ):
496 Launch a subprocess monitoring self process.
497 This monitoring subprocess is a python process lauching every intervalInMs ms evaluation of
498 CPU usage and RSS memory of the calling process.
499 Communication between subprocess and self is done by file.
503 outFileName (str) : name of file inside the results will be written. If None a new file is generated
505 See also FileSystemMonitoring
508 def BuildPythonFileForCPUPercent( intervalInMs, outFileName):
511 with tempfile.NamedTemporaryFile(prefix="cpu_mem_monitor_",suffix=".py") as f:
513 tempOutFile = outFileName
514 if tempOutFile is None:
515 tempOutFile = "{}.txt".format( os.path.splitext( tempPyFile )[0] )
517 with open(tempPyFile,"w") as f:
518 f.write("""import psutil
520 process = psutil.Process( pid )
522 with open("{}","a") as f:
523 f.write( "{{}}\\n".format( "{}" ) )
525 f.write( "{{}}\\n".format( str( process.cpu_percent() ) ) )
526 f.write( "{{}}\\n".format( str( process.memory_info().rss ) ) )
528 time.sleep( {} / 1000.0 )
529 """.format(pid, tempOutFile, intervalInMs, intervalInMs))
530 if outFileName is None:
531 autoOutFile = FileDeleter(tempOutFile)
533 autoOutFile = FileHolder(tempOutFile)
534 return FileDeleter(tempPyFile),autoOutFile
535 pyFileName, outFileName = BuildPythonFileForCPUPercent( intervalInMs, outFileName )
536 return MonitoringInfo(pyFileName, intervalInMs, outFileName, None)
538 class GenericPythonMonitoringLauncherCtxMgr:
539 def __init__(self, monitoringParams):
543 monitoringParams (MonitoringInfo)
545 self._monitoring_params = monitoringParams
548 pid = KernelBasis.LaunchMonitoring(self._monitoring_params.pyFileName.filename)
549 self._monitoring_params.pid = pid
550 return self._monitoring_params
552 def __exit__(self,exctype, exc, tb):
553 StopMonitoring( self._monitoring_params )
555 def StopMonitoring( monitoringInfo ):
557 Kill monitoring subprocess.
561 monitoringInfo (MonitoringInfo): info returned by LaunchMonitoring
564 KernelBasis.StopMonitoring(monitoringInfo.pid)
567 def __init__(self, intervalInMs, cpu, mem_rss):
572 cpu (list<float>) CPU usage
573 mem_rss (list<int>) rss memory usage
575 self._interval_in_ms = intervalInMs
576 self._data = [(a,b) for a,b in zip(cpu,mem_rss)]
578 st = """Interval in ms : {self.intervalInMs}
580 """.format( **locals() )
583 def intervalInMs(self):
584 return self._interval_in_ms
588 list of triplets. First param of pair is cpu usage
589 Second param of pair is memory usage
593 def ReadCPUMemInfoInternal( fileName ):
595 cpu = [] ; mem_rss = []
596 if os.path.exists( fileName ):
597 with open(fileName, "r") as f:
598 coarseData = [ elt.strip() for elt in f.readlines() ]
599 intervalInMs = int( coarseData[0] )
600 coarseData = coarseData[1:]
601 cpu = [float(elt) for elt in coarseData[::2]]
602 mem_rss = [ int(elt) for elt in coarseData[1::2]]
603 return CPUMemInfo(intervalInMs,cpu,mem_rss)
605 def ReadCPUMemInfo( monitoringInfo ):
607 Retrieve CPU/Mem data of monitoring.
611 monitoringInfo (MonitoringInfo): info returned by LaunchMonitoring
617 return ReadCPUMemInfoInternal( monitoringInfo.outFileName.filename )
620 def __init__(self, dirNameMonitored, intervalInMs, timeStamps, nbInodes, volumeOfDir):
624 timeStamps (list<datetimestruct>)
626 volumeOfDir (list<str>)
628 self._dir_name_monitored = dirNameMonitored
629 self._interval_in_ms = intervalInMs
630 self._data = [(t,a,b) for t,a,b in zip(timeStamps,nbInodes,volumeOfDir)]
632 st = """Filename monitored : {self.dirNameMonitored}
633 Interval in ms : ${self.intervalInMs}
635 """.format( **locals() )
638 def dirNameMonitored(self):
639 return self._dir_name_monitored
641 def intervalInMs(self):
642 return self._interval_in_ms
646 list of triplets. First param of triplet is datetimestruct
647 Second param of triplet is #inodes.
648 Thirst param of triplet is size.
652 def ReadInodeSizeInfoInternal( fileName ):
655 with open(fileName, "r") as f:
656 coarseData = [ elt.strip() for elt in f.readlines() ]
657 dirNameMonitored = coarseData[0] ; intervalInMs = int( coarseData[1] ) ; coarseData = coarseData[2:]
658 tss = [ datetime.datetime.fromtimestamp( float(elt) ) for elt in coarseData[::3] ]
659 nbInodes = [int(elt) for elt in coarseData[1::3]]
660 volumeOfDir = coarseData[2::3]
661 return InodeSizeInfo(dirNameMonitored,intervalInMs,tss,nbInodes,volumeOfDir)
663 def ReadInodeSizeInfo( monitoringInfo ):
665 Retrieve nb of inodes and size of monitoring
669 monitoringInfo (MonitoringInfo): info returned by LaunchMonitoring
675 return ReadInodeSizeInfoInternal( monitoringInfo.outFileName.filename )
677 class SeqByteReceiver:
678 # 2GB limit to trigger split into chunks
679 CHUNK_SIZE = 2000000000
680 def __init__(self,sender):
683 self._obj.UnRegister()
686 size = self._obj.getSize()
687 if size <= SeqByteReceiver.CHUNK_SIZE:
688 return self.fetchOneShot( size )
690 return self.fetchByChunks( size )
691 def fetchOneShot(self,size):
692 return self._obj.sendPart(0,size)
693 def fetchByChunks(self,size):
695 To avoid memory peak parts over 2GB are sent using EFF_CHUNK_SIZE size.
697 data_for_split_case = bytes(0)
698 EFF_CHUNK_SIZE = SeqByteReceiver.CHUNK_SIZE // 8
699 iStart = 0 ; iEnd = EFF_CHUNK_SIZE
700 while iStart!=iEnd and iEnd <= size:
701 part = self._obj.sendPart(iStart,iEnd)
702 data_for_split_case = bytes(0).join( [data_for_split_case,part] )
703 iStart = iEnd; iEnd = min(iStart + EFF_CHUNK_SIZE,size)
704 return data_for_split_case
706 class LogOfCurrentExecutionSession:
707 def __init__(self, handleToCentralizedInst):
708 self._remote_handle = handleToCentralizedInst
709 self._current_instance = ScriptExecInfo()
711 def addFreestyleAndFlush(self, value):
712 self._current_instance.freestyle = value
713 self.finalizeAndPushToMaster()
715 def addInfoOnLevel2(self, key, value):
716 setattr(self._current_instance,key,value)
718 def finalizeAndPushToMaster(self):
719 self._remote_handle.assign( pickle.dumps( self._current_instance ) )
721 class PyScriptNode_i (Engines__POA.PyScriptNode,Generic):
722 """The implementation of the PyScriptNode CORBA IDL that executes a script"""
723 def __init__(self, nodeName,code,poa,my_container,logscript):
724 """Initialize the node : compilation in the local context"""
725 Generic.__init__(self,poa)
726 self.nodeName=nodeName
728 self.my_container_py = my_container
729 self.my_container=my_container._container
730 linecache.cache[nodeName]=0,None,code.split('\n'),nodeName
731 self.ccode=compile(code,nodeName,'exec')
733 self.context[MY_CONTAINER_ENTRY_IN_GLBS] = self.my_container
734 self._log_script = logscript
735 self._current_execution_session = None
736 sys.stdout.flush() ; sys.stderr.flush() # flush to correctly capture log per execution session
739 # force removal of self.context. Don t know why it s not done by default
740 self.removeAllVarsInContext()
743 def getContainer(self):
744 return self.my_container
752 def defineNewCustomVar(self,varName,valueOfVar):
753 self.context[varName] = pickle.loads(valueOfVar)
756 def executeAnotherPieceOfCode(self,code):
757 """Called for initialization of container lodging self."""
759 ccode=compile(code,self.nodeName,'exec')
760 exec(ccode, self.context)
762 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"","PyScriptNode (%s) : code to be executed \"%s\"" %(self.nodeName,code),0))
764 def assignNewCompiledCode(self,codeStr):
767 self.ccode=compile(codeStr,self.nodeName,'exec')
769 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"","PyScriptNode.assignNewCompiledCode (%s) : code to be executed \"%s\"" %(self.nodeName,codeStr),0))
771 def executeSimple(self, key, val):
773 Same as execute method except that no pickelization mecanism is implied here. No output is expected
776 self.context.update({ "env" : [(k,v) for k,v in zip(key,val)]})
777 exec(self.ccode,self.context)
779 exc_typ,exc_val,exc_fr=sys.exc_info()
780 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
781 print("".join(l)) ; sys.stdout.flush() # print error also in logs of remote container
782 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s" % (self.nodeName),0))
784 def execute(self,outargsname,argsin):
785 """Execute the script stored in attribute ccode with pickled args (argsin)"""
787 argsname,kws=pickle.loads(argsin)
788 self.context.update(kws)
789 exec(self.ccode, self.context)
791 for arg in outargsname:
792 if arg not in self.context:
793 raise KeyError("There is no variable %s in context" % arg)
794 argsout.append(self.context[arg])
795 argsout=pickle.dumps(tuple(argsout),-1)
798 exc_typ,exc_val,exc_fr=sys.exc_info()
799 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
800 print("".join(l)) ; sys.stdout.flush() # print error also in logs of remote container
801 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s, outargsname: %s" % (self.nodeName,outargsname),0))
803 def executeFirst(self,argsin):
804 """ Same than first part of self.execute to reduce memory peak."""
805 def ArgInMananger(self,argsin):
806 argsInPy = SeqByteReceiver( argsin )
807 data = argsInPy.data()
808 self.addInfoOnLevel2("inputMem",len(data))
809 _,kws=pickle.loads(data)
812 self.beginOfCurrentExecutionSession()
813 self.addTimeInfoOnLevel2("startInputTime")
814 # to force call of SeqByteReceiver's destructor
815 kws = ArgInMananger(self,argsin)
816 vis = InOutputObjVisitor()
818 # fetch real data if necessary
819 kws[elt] = UnProxyObjectSimple( kws[elt],vis)
820 self.addInfoOnLevel2("inputHDDMem",vis)
821 self.context.update(kws)
822 self.addTimeInfoOnLevel2("endInputTime")
824 exc_typ,exc_val,exc_fr=sys.exc_info()
825 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
826 print("".join(l)) ; sys.stdout.flush() # print error also in logs of remote container
827 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode:First %s" % (self.nodeName),0))
829 def executeSecond(self,outargsname):
830 """ Same than second part of self.execute to reduce memory peak."""
833 self.addTimeInfoOnLevel2("startExecTime")
835 self.addInfoOnLevel2("measureTimeResolution",self.my_container_py.monitoringtimeresms())
836 with GenericPythonMonitoringLauncherCtxMgr( CPUMemoryMonitoring( self.my_container_py.monitoringtimeresms() ) ) as monitoringParams:
837 exec(self.ccode, self.context)
838 cpumeminfo = ReadCPUMemInfo( monitoringParams )
840 self.addInfoOnLevel2("CPUMemDuringExec",cpumeminfo)
842 self.addTimeInfoOnLevel2("endExecTime")
843 self.addTimeInfoOnLevel2("startOutputTime")
845 for arg in outargsname:
846 if arg not in self.context:
847 raise KeyError("There is no variable %s in context" % arg)
848 argsout.append(self.context[arg])
851 vis = InOutputObjVisitor()
853 # the proxy mecanism is catched here
854 argPickle = SpoolPickleObject( arg, vis )
855 retArg = SenderByte_i( self.poa,argPickle )
856 id_o = self.poa.activate_object(retArg)
857 retObj = self.poa.id_to_reference(id_o)
858 ret.append( retObj._narrow( SALOME.SenderByte ) )
859 outputMem += len(argPickle)
860 self.addInfoOnLevel2("outputMem",outputMem)
861 self.addInfoOnLevel2("outputHDDMem",vis)
862 self.addTimeInfoOnLevel2("endOutputTime")
863 self.endOfCurrentExecutionSession()
866 exc_typ,exc_val,exc_fr=sys.exc_info()
867 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
868 print("".join(l)) ; sys.stdout.flush() # print error also in logs of remote container
869 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode:Second %s, outargsname: %s" % (self.nodeName,outargsname),0))
871 def listAllVarsInContext(self):
873 pat = re.compile("^__([a-z]+)__$")
874 return [elt for elt in self.context if not pat.match(elt) and elt != MY_CONTAINER_ENTRY_IN_GLBS]
876 def removeAllVarsInContext(self):
877 for elt in self.listAllVarsInContext():
878 del self.context[elt]
880 def getValueOfVarInContext(self,varName):
882 return pickle.dumps(self.context[varName],-1)
884 exc_typ,exc_val,exc_fr=sys.exc_info()
885 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
886 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s" %self.nodeName,0))
889 def assignVarInContext(self, varName, value):
891 self.context[varName][0] = pickle.loads(value)
893 exc_typ,exc_val,exc_fr=sys.exc_info()
894 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
895 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s" %self.nodeName,0))
898 def callMethodOnVarInContext(self, varName, methodName, args):
900 return pickle.dumps( getattr(self.context[varName][0],methodName)(*pickle.loads(args)),-1 )
902 exc_typ,exc_val,exc_fr=sys.exc_info()
903 l=traceback.format_exception(exc_typ,exc_val,exc_fr)
904 raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s" %self.nodeName,0))
907 def beginOfCurrentExecutionSession(self):
908 self._current_execution_session = LogOfCurrentExecutionSession( self._log_script.addExecutionSession() )
909 self.context[MY_PERFORMANCE_LOG_ENTRY_IN_GLBS] = self._current_execution_session
911 def endOfCurrentExecutionSession(self):
912 self._current_execution_session.finalizeAndPushToMaster()
913 self._current_execution_session = None
915 def addInfoOnLevel2(self, key, value):
916 self._current_execution_session.addInfoOnLevel2(key, value)
918 def addTimeInfoOnLevel2(self, key):
919 from datetime import datetime
920 self._current_execution_session.addInfoOnLevel2(key,datetime.now())