Package PyFoam :: Package Execution :: Module FoamThread
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Execution.FoamThread

  1  #  ICE Revision: $Id$ 
  2  """Thread wrappers for OpenFOAM""" 
  3   
  4  import sys 
  5   
  6  from threading import Thread,Lock,Timer 
  7  from PyFoam.ThirdParty.six import print_ 
  8  from PyFoam.Error import warning,error 
  9   
 10  if sys.version_info<(2,4): 
 11      from popen2 import Popen4 
 12  else: 
 13      import subprocess 
 14   
 15  from time import time,sleep 
 16   
 17  try: 
 18      from resource import getrusage,getpagesize,RUSAGE_CHILDREN 
 19  except ImportError: 
 20      try: 
 21          from PyFoam.ThirdParty.winhacks import getrusage,getpagesize,RUSAGE_CHILDREN 
 22      except ImportError: 
 23          error("Unable to import working getrusage,getpagesize,RUSAGE_CHILDREN functions.") 
 24   
 25  from os import kill,path,unlink 
 26  from platform import uname 
 27  import signal 
 28   
 29  from PyFoam.Basics.LineReader import LineReader 
 30  from PyFoam.Infrastructure.Logging import foamLogger 
 31   
32 -def checkForStopFile(thrd):
33 """Checks for the file 'stop' in the directory of the FoamRun. If 34 it exists it is removed and the run is stopped gracefully""" 35 36 fName=path.join(thrd.runner.dir,"stop") 37 38 if path.exists(fName): 39 unlink(fName) 40 thrd.runner.stopGracefully() 41 return 42 43 fName=path.join(thrd.runner.dir,"write") 44 45 if path.exists(fName): 46 unlink(fName) 47 thrd.runner.writeResults() 48 49 thrd.timer2=Timer(thrd.timerTime,checkForStopFile,args=[thrd]) 50 thrd.timer2.start()
51
52 -def getLinuxMem(thrd):
53 """Reads the Memory usage of a thread on a linux-System 54 55 @param thrd: the thread object in question""" 56 57 # print "Timer called" 58 59 if not thrd.isLinux or thrd.threadPid<0: 60 return 61 62 mem=0 63 64 try: 65 t=open('/proc/%d/status' % thrd.threadPid) 66 v=t.read() 67 t.close() 68 # f=open('/tmp/test%dstatus' % thrd.threadPid,'w') 69 # f.write(v) 70 # f.close() 71 72 i=v.index('VmRSS') 73 tmp=v[i:].split() 74 if len(tmp)>=3: 75 mem=long(tmp[1]) 76 if tmp[2].lower()=='kb': 77 mem*=1024 78 elif tmp[2].lower()=='mb': 79 mem*=1024*1024 80 else: 81 mem=-1 82 except Exception: 83 e = sys.exc_info()[1] # compatible with 2.x and 3.x 84 print_("Getting LinuxMem:",e) 85 mem=-1 86 87 if mem>thrd.linuxMaxMem: 88 # print "Setting Memory to: ",mem 89 thrd.linuxMaxMem=mem 90 91 # print "Restarting Timer" 92 93 thrd.timer=Timer(thrd.timerTime,getLinuxMem,args=[thrd]) 94 thrd.timer.start()
95
96 -class FoamThread(Thread):
97 """Thread running an OpenFOAM command 98 99 The output of the command can be accessed in a thread-safe manner, 100 line by line 101 102 Designed to be used by the BasicRunner-class""" 103
104 - def __init__(self,cmdline,runner):
105 """@param cmdline:cmdline - Command line of the OpenFOAM command 106 @param runner: the Runner-object that started this thread""" 107 Thread.__init__(self) 108 self.cmdline=cmdline 109 self.runner=runner 110 self.output=None 111 self.reader=LineReader() 112 113 self.isLinux=False 114 self.isDarwin=False 115 self.isWindows=False 116 self.threadPid=-1 117 self.who=RUSAGE_CHILDREN 118 119 if uname()[0]=="Linux": 120 self.isLinux=True 121 self.linuxMaxMem=0 122 elif uname()[0]=="Darwin": 123 self.isDarwin=True 124 elif uname()[0]=="Windows": 125 self.isWindows=True 126 127 self.resStart=None 128 self.resEnd=None 129 130 self.timeStart=None 131 self.timeEnd=None 132 133 self.timerTime=5. 134 135 self.stateLock=Lock() 136 self.setState(False) 137 138 self.status=None 139 self.returncode=None 140 141 self.lineLock=Lock() 142 self.line="" 143 144 self.stateLock.acquire()
145
146 - def run(self):
147 """start the command""" 148 # print "Starting ",self.cmdline 149 self.resStart=getrusage(self.who) 150 self.timeStart=time() 151 152 if sys.version_info<(2,4): 153 run=Popen4(self.cmdline) 154 self.output=run.fromchild 155 else: 156 run=subprocess.Popen(self.cmdline,shell=True,bufsize=0, 157 stdin=subprocess.PIPE,stdout=subprocess.PIPE, 158 stderr=subprocess.STDOUT,close_fds=True) 159 self.output=run.stdout 160 self.run=run 161 self.threadPid=run.pid 162 foamLogger().info("Started with PID %d" % self.threadPid) 163 if self.isLinux: 164 # print "Starting Timer" 165 self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self]) 166 self.timer.start() 167 168 # print "Starting Timer" 169 self.timer2=Timer(0.5*self.timerTime,checkForStopFile,args=[self]) 170 self.timer2.start() 171 172 self.hasSomethingToSay=True 173 self.stateLock.release() 174 175 try: 176 # print "Waiting",time() 177 self.status=run.wait() 178 # Python 2.3 on Mac OS X never seems to reach this point 179 # print "After wait",time() 180 # print "Status:",self.status 181 182 # to give a chance to read the remaining output 183 if self.hasSomethingToSay: 184 sleep(2.) 185 while self.reader.read(self.output): 186 print_("Unused output:",self.reader.line) 187 except OSError: 188 e = sys.exc_info()[1] # compatible with 2.x and 3.x 189 print_("Exeption caught:",e) 190 191 self.stopTimer() 192 193 self.threadPid=-1 194 195 self.resEnd=getrusage(self.who) 196 self.timeEnd=time() 197 # print "End:",self.timeEnd 198 # print "Returned",self.status 199 200 self.getReturnCode()
201
202 - def getReturnCode(self):
203 if sys.version_info<(2,4): 204 # Don't know how to get the returncode from a Popen4-object 205 self.returncode=0 206 else: 207 self.returncode=self.run.returncode 208 return self.returncode
209
210 - def stopTimer(self):
211 if self.isLinux: 212 self.timer.cancel() 213 self.timer2.cancel()
214
215 - def read(self):
216 """read another line from the output""" 217 self.setState(self.reader.read(self.output)) 218 self.lineLock.acquire() 219 self.line=self.reader.line 220 self.lineLock.release()
221
222 - def getLine(self):
223 """gets the last line from the output""" 224 self.lineLock.acquire() 225 val=self.line 226 self.lineLock.release() 227 228 return val
229
230 - def interrupt(self):
231 """A keyboard-interrupt is reported""" 232 self.reader.wasInterupted=True 233 self.setState(False)
234
235 - def setState(self,state):
236 """sets the state of the thread (is there any more output)""" 237 self.stateLock.acquire() 238 self.hasSomethingToSay=state 239 if not self.hasSomethingToSay and self.timeStart and self.reader.wasInterupted: 240 if self.threadPid>0: 241 msg="Killing PID %d" % self.threadPid 242 print_(msg) 243 foamLogger().warning(msg) 244 try: 245 kill(self.threadPid,signal.SIGKILL) 246 except OSError: 247 warning("Process",self.threadPid,"was already dead") 248 249 # print "Set: ",state 250 self.stateLock.release()
251
252 - def check(self):
253 """@return: False if there is no more output of the command""" 254 self.stateLock.acquire() 255 state=self.hasSomethingToSay 256 # print "Get: ",state 257 self.stateLock.release() 258 259 return state
260
261 - def cpuTime(self):
262 """@return: number of seconds CPU-Time used""" 263 return self.cpuUserTime()+self.cpuSystemTime()
264
265 - def cpuUserTime(self):
266 """@return: number of seconds CPU-Time used in user mode""" 267 if self.resEnd==None: # and self.isDarwin: 268 # Mac OS X needs this (Ubuntu too?) 269 self.resEnd=getrusage(self.who) 270 if self.resStart==None or self.resEnd==None: 271 return 0 272 else: 273 return self.resEnd.ru_utime-self.resStart.ru_utime
274
275 - def cpuSystemTime(self):
276 """@return: number of seconds CPU-Time used in system mode""" 277 if self.resEnd==None: # and self.isDarwin: 278 # Mac OS X needs this (Ubuntu too?) 279 self.resEnd=getrusage(self.who) 280 if self.resStart==None or self.resEnd==None: 281 return 0 282 else: 283 return self.resEnd.ru_stime-self.resStart.ru_stime
284
285 - def usedMemory(self):
286 """@return: maximum resident set size in MegaByte""" 287 scale=1024.*1024. 288 if self.isLinux: 289 return self.linuxMaxMem/scale 290 291 if self.resStart==None or self.resEnd==None: 292 return 0. 293 else: 294 return getpagesize()*(self.resEnd.ru_maxrss-self.resStart.ru_maxrss)/scale
295
296 - def wallTime(self):
297 """@return: the wall-clock-time needed by the process""" 298 if self.timeEnd==None: # and self.isDarwin: 299 # Mac OS X needs this (Ubuntu too?) 300 self.timeEnd=time() 301 302 self.timeEnd=time() 303 304 # print "Wall:",self.timeEnd,self.timeStart 305 if self.timeStart==None or self.timeEnd==None: 306 return 0 307 else: 308 return self.timeEnd-self.timeStart
309