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
126 self.lineLock=Lock()
127 self.line=""
128
129 self.stateLock.acquire()
130
132 """start the command"""
133
134 self.resStart=getrusage(self.who)
135 self.timeStart=time()
136
137 if sys.version_info<(2,4):
138 run=Popen4(self.cmdline)
139 self.output=run.fromchild
140 else:
141 run=subprocess.Popen(self.cmdline,shell=True,bufsize=0,
142 stdin=subprocess.PIPE,stdout=subprocess.PIPE,
143 stderr=subprocess.STDOUT,close_fds=True)
144 self.output=run.stdout
145 self.threadPid=run.pid
146 foamLogger().info("Started with PID %d" % self.threadPid)
147 if self.isLinux:
148
149 self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self])
150 self.timer.start()
151
152
153 self.timer2=Timer(0.5*self.timerTime,checkForStopFile,args=[self])
154 self.timer2.start()
155
156 self.hasSomethingToSay=True
157 self.stateLock.release()
158
159 try:
160
161 self.status=run.wait()
162
163
164
165
166
167 if self.hasSomethingToSay:
168 sleep(2.)
169
170 while self.reader.read(self.output):
171 print "Unused output:",self.reader.line
172 except OSError,e:
173 print "Exeption caught:",e
174
175 self.stopTimer()
176
177 self.threadPid=-1
178
179 self.resEnd=getrusage(self.who)
180 self.timeEnd=time()
181
182
183
185 if self.isLinux:
186 self.timer.cancel()
187 self.timer2.cancel()
188
190 """read another line from the output"""
191 self.setState(self.reader.read(self.output))
192 self.lineLock.acquire()
193 self.line=self.reader.line
194 self.lineLock.release()
195
197 """gets the last line from the output"""
198 self.lineLock.acquire()
199 val=self.line
200 self.lineLock.release()
201
202 return val
203
205 """A keyboard-interrupt is reported"""
206 self.reader.wasInterupted=True
207 self.setState(False)
208
210 """sets the state of the thread (is there any more output)"""
211 self.stateLock.acquire()
212 self.hasSomethingToSay=state
213 if not self.hasSomethingToSay and self.timeStart and self.reader.wasInterupted:
214 if self.threadPid>0:
215 msg="Killing PID %d" % self.threadPid
216 print msg
217 foamLogger().warning(msg)
218 try:
219 kill(self.threadPid,signal.SIGKILL)
220 except OSError:
221 warning("Process",self.threadPid,"was already dead")
222
223
224 self.stateLock.release()
225
227 """@return: False if there is no more output of the command"""
228 self.stateLock.acquire()
229 state=self.hasSomethingToSay
230
231 self.stateLock.release()
232
233 return state
234
238
240 """@return: number of seconds CPU-Time used in user mode"""
241 if self.resEnd==None:
242
243 self.resEnd=getrusage(self.who)
244 if self.resStart==None or self.resEnd==None:
245 return 0
246 else:
247 return self.resEnd.ru_utime-self.resStart.ru_utime
248
250 """@return: number of seconds CPU-Time used in system mode"""
251 if self.resEnd==None:
252
253 self.resEnd=getrusage(self.who)
254 if self.resStart==None or self.resEnd==None:
255 return 0
256 else:
257 return self.resEnd.ru_stime-self.resStart.ru_stime
258
260 """@return: maximum resident set size in MegaByte"""
261 scale=1024.*1024.
262 if self.isLinux:
263 return self.linuxMaxMem/scale
264
265 if self.resStart==None or self.resEnd==None:
266 return 0.
267 else:
268 return getpagesize()*(self.resEnd.ru_maxrss-self.resStart.ru_maxrss)/scale
269
271 """@return: the wall-clock-time needed by the process"""
272 if self.timeEnd==None:
273
274 self.timeEnd=time()
275
276 self.timeEnd=time()
277
278
279 if self.timeStart==None or self.timeEnd==None:
280 return 0
281 else:
282 return self.timeEnd-self.timeStart
283