Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / testing / performance / talos / cmanager_linux.py
blob92ba71288b8bef6aec1b8d1cd21e37e17df7ea8f
1 #!/usr/bin/env python
3 # ***** BEGIN LICENSE BLOCK *****
4 # Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 # The contents of this file are subject to the Mozilla Public License Version
7 # 1.1 (the "License"); you may not use this file except in compliance with
8 # the License. You may obtain a copy of the License at
9 # http://www.mozilla.org/MPL/
11 # Software distributed under the License is distributed on an "AS IS" basis,
12 # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 # for the specific language governing rights and limitations under the
14 # License.
16 # The Original Code is standalone Firefox Windows performance test.
18 # The Initial Developer of the Original Code is Google Inc.
19 # Portions created by the Initial Developer are Copyright (C) 2006
20 # the Initial Developer. All Rights Reserved.
22 # Contributor(s):
23 # Annie Sullivan <annie.sullivan@gmail.com> (original author)
24 # Ben Hearsum <bhearsum@wittydomain.com> (ported to linux)
26 # Alternatively, the contents of this file may be used under the terms of
27 # either the GNU General Public License Version 2 or later (the "GPL"), or
28 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 # in which case the provisions of the GPL or the LGPL are applicable instead
30 # of those above. If you wish to allow use of your version of this file only
31 # under the terms of either the GPL or the LGPL, and not to allow others to
32 # use your version of this file under the terms of the MPL, indicate your
33 # decision by deleting the provisions above and replace them with the notice
34 # and other provisions required by the GPL or the LGPL. If you do not delete
35 # the provisions above, a recipient may use your version of this file under
36 # the terms of any one of the MPL, the GPL or the LGPL.
38 # ***** END LICENSE BLOCK *****
40 """A set of functions to run the Tp test.
42 The Tp test measures page load times in Firefox. It does this with a
43 JavaScript script that opens a new window and cycles through page loads
44 from the local disk, timing each one. The script dumps the sum of the
45 mean times to open each page, and the standard deviation, to standard out.
46 We can also measure performance attributes during the test. See below for
47 what can be monitored
48 """
50 __author__ = 'annie.sullivan@gmail.com (Annie Sullivan)'
52 import subprocess
53 import sys
54 import os
55 import time
56 import threading
58 import ffprocess
60 def GetPrivateBytes(pid):
61 """Calculate the amount of private, writeable memory allocated to a process.
62 This code was adapted from 'pmap.c', part of the procps project.
63 """
64 mapfile = '/proc/%s/maps' % pid
65 maps = open(mapfile)
67 private = 0
69 for line in maps:
70 # split up
71 (range,line) = line.split(" ", 1)
73 (start,end) = range.split("-")
74 flags = line.split(" ", 1)[0]
76 size = int(end, 16) - int(start, 16)
78 if flags.find("p") >= 0:
79 if flags.find("w") >= 0:
80 private += size
82 return private
85 def GetResidentSize(pid):
86 """Retrieve the current resident memory for a given process"""
87 # for some reason /proc/PID/stat doesn't give accurate information
88 # so we use status instead
89 file = '/proc/%s/status' % pid
91 status = open(file)
93 for line in status:
94 if line.find("VmRSS") >= 0:
95 return int(line.split()[1]) * 1024
98 def GetCpuTime(pid, sampleTime=1):
99 # return all zeros on this platform as per the 7/18/07 perf meeting
100 return 0
102 def GetXRes(pid):
103 """Returns the total bytes used by X"""
104 try:
105 cmdline = "xrestop -m 1 -b | grep -A 15 " + str(pid) + " | tr -d \"\n\" | sed \"s/.*total bytes.*: ~//g\""
106 pipe = subprocess.Popen(cmdline, shell=True, stdout=-1).stdout
107 data = pipe.read()
108 pipe.close()
109 return data
110 except:
111 print "Unexpected error:", sys.exc_info()
112 return -1
114 counterDict = {}
115 counterDict["Private Bytes"] = GetPrivateBytes
116 counterDict["RSS"] = GetResidentSize
117 counterDict["% Processor Time"] = GetCpuTime
118 counterDict["XRes"] = GetXRes
120 class CounterManager(threading.Thread):
121 """This class manages the monitoring of a process with any number of
122 counters.
124 A counter can be any function that takes an argument of one pid and
125 returns a piece of data about that process.
126 Some examples are: CalcCPUTime, GetResidentSize, and GetPrivateBytes
129 pollInterval = .25
131 def __init__(self, process, counters=None):
132 """Args:
133 counters: A list of counters to monitor. Any counters whose name does
134 not match a key in 'counterDict' will be ignored.
136 self.allCounters = {}
137 self.registeredCounters = {}
138 self.process = process
139 self.runThread = False
140 self.pid = -1
142 self._loadCounters()
143 self.registerCounters(counters)
145 threading.Thread.__init__(self)
147 def _loadCounters(self):
148 """Loads all of the counters defined in the counterDict"""
149 for counter in counterDict.keys():
150 self.allCounters[counter] = counterDict[counter]
152 def registerCounters(self, counters):
153 """Registers a list of counters that will be monitoring.
154 Only counters whose names are found in allCounters will be added
156 for counter in counters:
157 if counter in self.allCounters:
158 self.registeredCounters[counter] = \
159 [self.allCounters[counter], []]
161 def unregisterCounters(self, counters):
162 """Unregister a list of counters.
163 Only counters whose names are found in registeredCounters will be
164 paid attention to
166 for counter in counters:
167 if counter in self.registeredCounters:
168 del self.registeredCounters[counter]
170 def getRegisteredCounters(self):
171 """Returns a list of the registered counters."""
172 return keys(self.registeredCounters)
174 def getCounterValue(self, counterName):
175 """Returns the last value of the counter 'counterName'"""
176 try:
177 if counterName is "% Processor Time":
178 return self._getCounterAverage(counterName)
179 else:
180 return self.registeredCounters[counterName][1][-1]
181 except:
182 return None
184 def _getCounterAverage(self, counterName):
185 """Returns the average value of the counter 'counterName'"""
186 try:
187 total = 0
188 for v in self.registeredCounters[counterName][1]:
189 total += v
190 return total / len(self.registeredCounters[counterName][1])
191 except:
192 return None
194 def getProcess(self):
195 """Returns the process currently associated with this CounterManager"""
196 return self.process
198 def startMonitor(self):
199 """Starts the monitoring process.
200 Throws an exception if any error occurs
202 # TODO: make this function less ugly
203 try:
204 # the last process is the useful one
205 self.pid = ffprocess.GetPidsByName(self.process)[-1]
206 os.stat('/proc/%s' % self.pid)
207 self.runThread = True
208 self.start()
209 except:
210 print 'WARNING: problem starting counter monitor'
212 def stopMonitor(self):
213 """Stops the monitor"""
214 # TODO: should probably wait until we know run() is completely stopped
215 # before setting self.pid to None. Use a lock?
216 self.runThread = False
218 def run(self):
219 """Performs the actual monitoring of the process. Will keep running
220 until stopMonitor() is called
222 while self.runThread:
223 for counter in self.registeredCounters.keys():
224 # counter[0] is a function that gets the current value for
225 # a counter
226 # counter[1] is a list of recorded values
227 try:
228 self.registeredCounters[counter][1].append(
229 self.registeredCounters[counter][0](self.pid))
230 except:
231 # if a counter throws an exception, remove it
232 self.unregisterCounters([counter])
234 time.sleep(self.pollInterval)