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