1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import os, sys, string, time, thread
21
22 from pysys.constants import *
23
24
26 """Process monitor for the logging of process statistics.
27
28 The process monitor uses either the win32pdh module (windows systems) or the ps command line utility
29 (unix systems) to obtain and log to file statistics on a given process as determined by the process id.
30 Usage of the class is to create an instance specifying the process id, the logging interval and the log
31 file. Once created, the process monitor is started and stopped via its L{start} and L{stop} methods.
32 Process monitors are started as a separate thread, so control passes back to the caller of the start method
33 immediately.
34
35 On windows systems, statistics obtained include the CPU usage (%), the working set (memory pages allocated),
36 the virtual bytes (virtual address space including shared memory segments), the private bytes (virtual
37 address space not including shared memory segments), the number of process threads and the number of
38 handles. All memory values are quoted in KBytes and the CPU precentage represents the usage over all available
39 processors. A CPU usage of 100% represents a single CPU fully utilized; it is therefore possible to obtain CPU
40 usage figures of over 100% on multi-core processors. The format of the log file is tab separated, with
41 timestamps used to denote the time each measurement was obtained, e.g. ::
42
43 Time CPU Working Virtual Private Threads Handles
44 ------------------------------------------------------------------------
45 09/16/08 14:20:44 80 125164 212948 118740 44 327
46 09/16/08 14:20:49 86 125676 213972 120128 44 328
47 09/16/08 14:20:54 84 125520 212948 119116 44 328
48 09/16/08 14:20:59 78 125244 212948 119132 44 328
49
50
51 On unix systems, statistics obtained include the CPU usage (%), the resident memory (via the rss format specifier
52 to ps), and the virtual memory (via the vsz format spepcifier to ps). All memory values are quoted in KBytes and
53 the CPU precentage represents the usage over all available processors. A CPU usage of 100% represents a single
54 CPU fully utilized; it is therefore possible to obtain CPU usage figures of over 100% on multi-core processors.
55 The format of the log file is tab separated, with timestamps used to denote the time each measurement was obtained,
56 e.g. ::
57
58 Time CPU Resident Virtual
59 ----------------------------------------------------
60 09/16/08 14:24:10 69.5 89056 1421672
61 09/16/08 14:24:20 73.1 101688 1436804
62 09/16/08 14:24:30 82.9 102196 1436516
63 09/16/08 14:24:40 89.1 102428 1436372
64 09/16/08 14:24:50 94.2 104404 1438420
65
66
67 Both windows and unix operating systems support the numProcessors argument in the variable argument list in order
68 to normalise the CPU statistics gathered by the number of available CPUs.
69
70 """
71
72 - def __init__(self, pid, interval, file=None, **kwargs):
73 """Construct an instance of the process monitor.
74
75 @param pid: The process id to monitor
76 @param interval: The interval in seconds to record the process statistics
77 @param file: The full path to the file to log the process statistics
78 @param kwargs: Keyword arguments to allow platform specific configurations
79
80 """
81 self.pid = pid
82 self.interval = interval
83 if file:
84 self.file = open(file, 'w', 0)
85 else:
86 self.file = sys.stdout
87
88
89 self.numProcessors=1
90 if kwargs.has_key("numProcessors"):
91 self.numProcessors = int(kwargs["numProcessors"])
92
93
95 children = []
96 children.append(int(parentPid))
97
98 for i in range(1, len(psList)):
99 pid = int(string.split(psList[i])[0])
100 ppid = int(string.split(psList[i])[1])
101 if ppid == parentPid:
102 children[len(children):] = self.__findChildren(psList, pid)
103
104 return children
105
106
108
109 time.sleep(1)
110
111
112 if (includeChildren):
113 fp = os.popen("ps -o pid,ppid")
114 psList = fp.readlines()
115 fp.close()
116 pidTree = self.__findChildren(psList, pid)
117 else:
118 pidTree = [pid]
119
120
121 while self.active:
122 data = [0, 0, 0]
123 fp = os.popen("ps -o pid,pcpu,rss,vsz")
124 info = fp.readlines()
125 fp.close()
126
127 for i in range(1, len(info)):
128 if int(string.split(info[i])[0]) in pidTree:
129 data[0] = data[0] + float(string.split(info[i])[1])
130 data[1] = int(string.split(info[i])[2])
131 data[2] = int(string.split(info[i])[3])
132
133 currentTime = time.strftime("%m/%d/%y %H:%M:%S", time.gmtime(time.time()))
134 file.write( "%s\t%f\t%d\t%d\n" % (currentTime, data[0]/self.numProcessors, data[1], data[2]) )
135 time.sleep(interval)
136
137
138 if file != sys.stdout: file.close()
139
140
142
143 data = [-1, -1, -1]
144 while self.active:
145 try:
146 fp = os.popen("ps -p %s -o pcpu,rss,vsz" % (pid))
147 info = fp.readlines()[1]
148 for i in range(len(data)):
149 data[i] = string.split(info)[i]
150 fp.close()
151 except:
152 fp.close()
153 currentTime = time.strftime("%m/%d/%y %H:%M:%S", time.gmtime(time.time()))
154 file.write( "%s\t%s\t%s\t%s\n" % (currentTime, data[0]/self.numProcessors, data[1], data[2]) )
155 time.sleep(interval)
156
157
158
160 """Return the running status of the process monitor.
161
162 @return: The running status (True | False)
163 @rtype: integer
164 """
165 return self.active
166
167
169 """Start the process monitor.
170
171 """
172 self.active = 1
173 if PLATFORM == 'sunos':
174 thread.start_new_thread(self.__solarisLogProfile, (self.pid, self.interval, self.file))
175 elif PLATFORM in ['linux','darwin']:
176 thread.start_new_thread(self.__linuxLogProfile, (self.pid, self.interval, self.file))
177
178
180 """Stop the process monitor.
181
182 """
183 self.active = 0
184
185
186
187
188
189 if __name__ == "__main__":
190 if len(sys.argv) < 5:
191 print "Usage: monprocess.py <pid> <interval> <duration> <filename>"
192 else:
193 try:
194 pid = int(sys.argv[1])
195 interval = int(sys.argv[2])
196 duration = int(sys.argv[3])
197 file = sys.argv[4]
198 except:
199 print "Process ID, interval and duration should be valid integers"
200 sys.exit(-1)
201
202 monitor = ProcessMonitor(pid, interval, file)
203 monitor.start()
204 time.sleep(duration)
205 monitor.stop()
206