1
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
51
53 """Reads the Memory usage of a thread on a linux-System
54
55 @param thrd: the thread object in question"""
56
57
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
69
70
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]
84 print_("Getting LinuxMem:",e)
85 mem=-1
86
87 if mem>thrd.linuxMaxMem:
88
89 thrd.linuxMaxMem=mem
90
91
92
93 thrd.timer=Timer(thrd.timerTime,getLinuxMem,args=[thrd])
94 thrd.timer.start()
95
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
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
147 """start the command"""
148
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
165 self.timer=Timer(0.1*self.timerTime,getLinuxMem,args=[self])
166 self.timer.start()
167
168
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
177 self.status=run.wait()
178
179
180
181
182
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]
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
198
199
200 self.getReturnCode()
201
203 if sys.version_info<(2,4):
204
205 self.returncode=0
206 else:
207 self.returncode=self.run.returncode
208 return self.returncode
209
211 if self.isLinux:
212 self.timer.cancel()
213 self.timer2.cancel()
214
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
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
231 """A keyboard-interrupt is reported"""
232 self.reader.wasInterupted=True
233 self.setState(False)
234
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
250 self.stateLock.release()
251
253 """@return: False if there is no more output of the command"""
254 self.stateLock.acquire()
255 state=self.hasSomethingToSay
256
257 self.stateLock.release()
258
259 return state
260
264
266 """@return: number of seconds CPU-Time used in user mode"""
267 if self.resEnd==None:
268
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
276 """@return: number of seconds CPU-Time used in system mode"""
277 if self.resEnd==None:
278
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
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
297 """@return: the wall-clock-time needed by the process"""
298 if self.timeEnd==None:
299
300 self.timeEnd=time()
301
302 self.timeEnd=time()
303
304
305 if self.timeStart==None or self.timeEnd==None:
306 return 0
307 else:
308 return self.timeEnd-self.timeStart
309