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 while self.reader.read(self.output):
170 print "Unused output:",self.reader.line
171 except OSError,e:
172 print "Exeption caught:",e
173
174 self.stopTimer()
175
176 self.threadPid=-1
177
178 self.resEnd=getrusage(self.who)
179 self.timeEnd=time()
180
181
182
184 if self.isLinux:
185 self.timer.cancel()
186 self.timer2.cancel()
187
189 """read another line from the output"""
190 self.setState(self.reader.read(self.output))
191 self.lineLock.acquire()
192 self.line=self.reader.line
193 self.lineLock.release()
194
196 """gets the last line from the output"""
197 self.lineLock.acquire()
198 val=self.line
199 self.lineLock.release()
200
201 return val
202
204 """A keyboard-interrupt is reported"""
205 self.reader.wasInterupted=True
206 self.setState(False)
207
209 """sets the state of the thread (is there any more output)"""
210 self.stateLock.acquire()
211 self.hasSomethingToSay=state
212 if not self.hasSomethingToSay and self.timeStart and self.reader.wasInterupted:
213 if self.threadPid>0:
214 msg="Killing PID %d" % self.threadPid
215 print msg
216 foamLogger().warning(msg)
217 try:
218 kill(self.threadPid,signal.SIGKILL)
219 except OSError:
220 warning("Process",self.threadPid,"was already dead")
221
222
223 self.stateLock.release()
224
226 """@return: False if there is no more output of the command"""
227 self.stateLock.acquire()
228 state=self.hasSomethingToSay
229
230 self.stateLock.release()
231
232 return state
233
237
239 """@return: number of seconds CPU-Time used in user mode"""
240 if self.resEnd==None:
241
242 self.resEnd=getrusage(self.who)
243 if self.resStart==None or self.resEnd==None:
244 return 0
245 else:
246 return self.resEnd.ru_utime-self.resStart.ru_utime
247
249 """@return: number of seconds CPU-Time used in system mode"""
250 if self.resEnd==None:
251
252 self.resEnd=getrusage(self.who)
253 if self.resStart==None or self.resEnd==None:
254 return 0
255 else:
256 return self.resEnd.ru_stime-self.resStart.ru_stime
257
259 """@return: maximum resident set size in MegaByte"""
260 scale=1024.*1024.
261 if self.isLinux:
262 return self.linuxMaxMem/scale
263
264 if self.resStart==None or self.resEnd==None:
265 return 0.
266 else:
267 return getpagesize()*(self.resEnd.ru_maxrss-self.resStart.ru_maxrss)/scale
268
270 """@return: the wall-clock-time needed by the process"""
271 if self.timeEnd==None:
272
273 self.timeEnd=time()
274
275 self.timeEnd=time()
276
277
278 if self.timeStart==None or self.timeEnd==None:
279 return 0
280 else:
281 return self.timeEnd-self.timeStart
282