/usr/share/pyshared/MoinMoin/util/profile.py is in python-moinmoin 1.9.3-1ubuntu2.3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | """ profile - moin profiling utilities
This module provides profilers used to profile the memory usage of a
long running process.
Typical usage:
1. Create a profiler:
from MoinMoin.util.profile import Profiler
profiler = Profiler('my log')
2. In the request handler, add each request to the profiler:
profiler.addRequest()
3. If you like, you can add extra samples:
profiler.sample()
You can customize the profiler when you create it:
* requestsPerSample (default 100):
How many requests to run between samples. Set higher for live wiki or
lower for more accurate results.
* collect (default 0):
Use gc.collect to force a memory cleanup each sample. Keeps the
memory usage much lower, but your profile data will not reflect the
real world memory usage of the application.
Based on code by Oliver Graf
@copyright: 2004 Nir Soffer
@license: GNU GPL, see COPYING for details.
"""
import os, time, gc
class Profiler:
""" Profile memory usage
Profiler count requests and sample memory usage.
FIXME: We might want to save the profiler log in the profiled wiki
data dir, but the data dir is available only later in request. This
should be fixed by loading the config earlier.
"""
def __init__(self, name, requestsPerSample=100, collect=0):
""" Initialize a profiler
@param name: profiler name, used in the log file name
@param requestsPerSample: how many request to run between samples
@param collect: should call gc.collect() in each sample
"""
logname = '%s--%s.log' % (name, time.strftime('%Y-%m-%d--%H-%M'))
self.logfile = file(logname, 'a')
self.requestsPerSample = requestsPerSample
self.collect = collect
self.pid = os.getpid()
self.count = 0 # count between somples
self.requests = 0 # requests added
self.data = {'collect': 'NA'} # Sample data
def addRequest(self):
""" Add a request to the profile
Call this for each page request.
WARNING: This is the most important call. if you don't call this
for each request - you will not have any profile data.
Invoke sample when self.count reach self.requestsPerSample.
"""
self.requests += 1
self.count += 1
if self.count == self.requestsPerSample:
# Time for a sample
self.count = 0
self.sample()
def sample(self):
""" Make a sample of memory usage and log it
You can call this to make samples between the samples done each
requestsPerSample, for example, at startup.
Invoke common methods for all profilers. Some profilers like
TwistedProfiler override this method.
"""
self._setData()
self._setMemory()
self._log()
# Private methods ------------------------------------------------------
def _setData(self):
""" Collect sample data into self.data
Private method used by profilers.
"""
d = self.data
d['date'] = time.strftime('%Y-%m-%d %H:%M:%S')
d['requests'] = self.requests
if self.collect:
d['collect'] = str(gc.collect())
d['objects'] = len(gc.get_objects())
d['garbage'] = len(gc.garbage)
def _setMemory(self):
""" Get process memory usage
Private method used by profilers.
Uses ps call, maybe we should use procfs on Linux or maybe
getrusage system call (using the ctypes module).
"""
lines = os.popen('/bin/ps -p %s -o rss' % self.pid).readlines()
self.data['memory'] = lines[1].strip()
def _log(self):
""" Format sample and write to log
Private method used by profilers.
"""
line = ('%(date)s req:%(requests)d mem:%(memory)sKB collect:%(collect)s '
'objects:%(objects)d garbage:%(garbage)d\n' % self.data)
self.logfile.write(line)
self.logfile.flush()
class TwistedProfiler(Profiler):
""" Twisted specific memory profiler
Customize the way we call ps, to overcome blocking problems on
twisted.
"""
def __init__(self, name, requestsPerSample=100, collect=0):
""" Initialized twisted profiler
Invoke Profiler.__init__ and import getProcessOuput from
twisted.
"""
Profiler.__init__(self, name, requestsPerSample, collect)
from twisted.internet.utils import getProcessOutput
self._getProcessOutput = getProcessOutput
def sample(self):
""" Make a sample of memory usage and log it
On twisted we can't just call ps - we have to use deferred,
which will call us using a callback when its finished, and then
we log.
Since twisted continue to serve while the deferred fetch the
memory, the reading may be late in few requests.
"""
self._setData()
# Memory will be available little later
deferred = self._getProcessOutput('/bin/ps',
('-p', str(self.pid), '-o', 'rss'))
deferred.addCallback(self._callback)
# Private methods ------------------------------------------------------
def _callback(self, data):
""" Called from deferred when ps output is available
Private method, don't call this.
"""
self.data['memory'] = data.split('\n')[1].strip()
self._log()
if __name__ == '__main__':
# In case someone try to run as a script
print __doc__
|